Ad

Props Passed From Parent To Child And Setting Those Props In State Does Not Work Immediately

I am building an app where I get "complaints" from my Nodejs app. Then I pass those complaints to child component as props. In child component, I set those props to state in ComponentDidMount(). But render() function gets called first so it does not show anything on screen. State is not set immediately. please help. I am struggling from 2 days.

this is parent component

class Complainer extends Component {
  state = {
    complaints: []
  };

  async componentDidMount() {
    try {
      const user = auth.getCurrentUser();
      console.log(user);
      this.setState({ user });
      if (!user || user.role !== 'complainer') this.props.history.replace('/');
    } catch (ex) {
      window.location = '/login';
    }

    const { data: complaints } = await getComplaints();
    this.setState({ complaints });
  }

  render() {
    const { complaints } = this.state;
    return (
      <React.Fragment>
        <Navbar user={this.state.user} />
        <div className="container">
          <Switch>
            <Route
              path="/complainer/view-all"
              render={props => (
                <AllComplaints complaints={complaints} {...props} />
              )}
            />
            <Route path="/complainer/new-complaint" component={ComplaintForm} />
            <Route path="/complainer/not-found" component={notfound} />
            <Showcase user={this.state.user} />
          </Switch>
          <hr />
        </div>
      </React.Fragment>
    );
  }
}

export default Complainer;

This is child

class AllComplaints extends Component {
  state = {
    data: {
      columns: [
        {
          label: 'location',
          field: 'location',
          sort: 'asc',
          width: 280
        },
        {
          label: 'Title',
          field: 'title',
          sort: 'asc',
          width: 150
        }
      ],

      rows: []
    }
  };

  componentDidMount() {
    const { complaints } = this.props;
    this.setState({ rows: complaints });
  }

  render() {
    const { data } = this.state;
    return (
      <React.Fragment>
        {data.rows && <MDBDataTable striped bordered small data={data} />}
        {!data.rows && <h1>There is no complaints to show</h1>}
      </React.Fragment>
    );
  }
}

export default AllComplaints;

The problem is, as in state, rows are empty .i.e. []. in componentDidMount() I am setting the coming props to state of this "AllComplaints" component.

I want to set the "props" value to "this.state.data.rows". But this is not happening. It takes time to set but render() is called first so it shows nothing on the screen.

Please help.

Ad

Answer

Two things:

As @karahan mentioned, you're not setting your state correctly.

this.setState({ rows: complaints });

should be something like:

this.setState(prevState => { data: { ...prevState.data, rows: complaints } });

This probably won't be sufficient however. You're retrieving your data in componentDidMount of the parent, and setting your state in componentDidMount of the child. However, the componentDidMount of the child is always run first if they're mounted at the same time, and is only run once. This means that with your setup, your child's props.complaints has the potential to be empty in componentDidMount.

I'd solve this by not using state in your child's component. There's rarely a good reason to store the same state in multiple components (in this case, you're storing the same thing in both the parent and the child). Just use your props, which will always be up-to-date in your render function. Your rendering of MDBDataTable should probably look something like this:

<MDBDataTable striped bordered small data={{ ...this.state.data, rows: this.props.complaints }} />

If you absolutely must store complaints in the state of the child for some reason, you should either fetch the data in the child instead, or look into getDerivedStateFromProps and componentDidUpdate. However, its unlikely that you need such a setup.

Ad
source: stackoverflow.com
Ad