Home > Software design >  React: Rendering a list of components by passing the list as a prop
React: Rendering a list of components by passing the list as a prop

Time:02-14

I'm currently following a tutorial on React and am interested as to how this is possible:

class Counters extends Component {
  state = {
    counters: [
      { id: 0, value: 0 },
      { id: 1, value: 4 },
      { id: 2, value: 5 },
      { id: 3, value: 9 },
    ],
  };

  handleDelete = (counterID) => {
      console.log("Event handler called", counterID);
      const counters = this.state.counters.filter((c) => c.id !== counterID);
      this.setState({ counters });
  };

render() {
    return (
      <React.Fragment>
        {this.state.counters.map((counters) => (
          <Counter
            key={counters.id}
            counters={counters}
            onDelete={this.handleDelete}
          ></Counter>
        ))}
      </React.Fragment>
    );
  }

I am using the "Counters" to keep track of my individual "Counter" (notice the singular noun) components. I am interested to know why is it that I can simply pass the entire array as a prop into "Counter" with this line:

counters={counters}

and with the following code in the "Counter" class:

class Counter extends Component {
  state = {
    value: this.props.counters.value,
    tags: ["tag1", "tag2", "tag3"],
  };

  styles = {
    fontSize: "50px",
    fontWeight: "bolder",
  };
  
  handleIncrement() {
    console.log("Increment clicked.");
    this.setState({ value: this.state.count   1 });
  }

  render() {
    console.log(this.props);
    return (
      <React.Fragment>
        <h4>Counter #{this.props.counters.id}</h4>
        <span style={{ fontSize: "25px" }} className={this.getBadgeClasses()}>
          {this.formatCount()}
        </span>
        <button
          onClick={() => this.handleIncrement()}
          className="btn btn-secondary btn-sm m-2"
        >
          Increment
        </button>
        <button
          onClick={() => this.props.onDelete(this.props.counters.id)}
          className="btn btn-danger btn-sm m-2"
        >
          Delete
        </button>
        {this.renderTags()}
      </React.Fragment>
    );
  }

  getTags() {
    let tags = this.state.tags;
    return tags === undefined || tags.length <= 0 ? (
      <p>"The tag list is empty."</p>
    ) : (
      tags.map((tag) => <li key={tag}>{tag}</li>)
    );
  }

  renderTags() {
    return <ul>{this.getTags()}</ul>;
  }

  getBadgeClasses() {
    let classes = "badge m-2 badge-";
    classes  = this.state.value === 0 ? "warning" : "primary";
    return classes;
  }

  formatCount() {
    const value = this.state.value;
    return value === 0 ? "Zero" : value;
  }
}

export default Counter;

I am able to get an entire list of "Counter" components rendered? I was under the impression I only declared a single in the "Counters" class, yet by passing a list I am able to render an entire list of Counters. How is this possible? What concept am I missing here?

CodePudding user response:

If you want past the entire list on Counter component :

counters={this.state.counters}

Because with counter={counters} you past in fact one element (method map send on item by one item). So in fact, when you write this.state.counters.map((counters) => ..., you should write this.state.counters.map((counter) =>... because it's just one element of array counters.

  • Related