ImportError
ImportError

Reputation: 365

Render child component in parent after re-rendering sibling component

I have a parent component housing two children components(AddPersonForm and PeopleList). When I submit a name via the AddPersonForm, I expect it to be rendered in the PeopleList component, but it doesn't.

Here is my AddPersonForm:

class AddPersonForm extends React.Component {
   state = {
      person: "" 
   } 
   
   handleChange = (e) => this.setState({person: e.target.value});

   handleSubmit = (e) => {
      if(this.state.person != '') {
         this.props.parentMethod(this.state.person);
         this.setState({person: ""});
      } 
      e.preventDefault();
  } 

   render() {
      return (
         <form onSubmit={this. handleSubmit}>
            <input type="text" placeholder="Add new contact" onChange={this.handleChange} value={this.state.person} />
            <button type="submit">Add</button>
         </form>
     );
  }   

My PeopleList component:

class PeopleList extends React.Component {
   constructor(props) {
      super(props);
      const arr = this.props.data;

      this.state = {
         listItems: arr.map((val, index) => <li key={index}>{val}</li>  );
      } 
   }    

   render() {
      return <ul>{this.state.listItems}</ul>;
   } 
} 

Now the parent component, ContactManager:

class ContactManager  extends React.Component {
   state = {
      contacts: this.props.data
   } 
   
   addPerson = (name) => {
      this.setState({contacts: [... this.state.contacts, name]});

   render() {
      return (
         <div>
            <AddPersonForm parentMethod={this. addPerson}×/>
            <PeopleList data={this.state.contacts} />
         </div>
     );

Please what I'm I doing wrong, or not doing?

Upvotes: 0

Views: 941

Answers (2)

lawrence-witt
lawrence-witt

Reputation: 9354

The issue is in your PeopleList component. The state object which renders your list is created in the constructor when the component mounts, but you have no way of updating it when it recieves new values. It will always give you the initial value.

You could introduce a lifecycle method, componentDidUpdate, which would allow you to compare the previous props to the new props when they arrive, and update the state accordingly. I would recommend you not do this for two reasons:

  1. Storing props directly in a components state is not good practice. You are just creating a copy of the state in the component above and that creates opportunities for confusion and stale values when one of them updates. Ideally, each piece of data should live in only one place.

  2. If all PeopleList is doing is rendering your data, then it doesn't need any state at all. It can act as a display component that maps your props in place and doesn't have to worry about updating itself or managing its own data. This would actually make it a good candidate for conversion into a functional component.

class PeopleList extends React.Component {
  render() {
    return (
      <ul>
        {this.props.data.map((val, index) => (
          <li key={index}>{val}</li>
        ))}
      </ul>
    );
  }
}

Upvotes: 1

Xesenix
Xesenix

Reputation: 2548

You are initializing PeopleList with props when its created and mounted but then you are not using new values of props for updating it.

To fix your issue use current value of prop when rendering:

class PeopleList extends React.Component {
   render() {
      return <ul>{ this.props.data.map((val, index) => <li key={index}>{val}</li>) }</ul>;
   } 
}

Upvotes: 1

Related Questions