Search code examples
reactjsflux

Correct approach for using flux and component lifecycle


I'm migrating the code from what I see on here on CodePen.

Within IssueBox, I am planning to implement a form which an enduser will update setting a state from 'unverified' to 'verified'.

App (ill rename this component) will be my parent and IssueBox would be the child.

So I got through flux => Action -> dispatcher -> udpate db -> update view.

Now that I have the new state and the view should be updated, do I use componentWillRecieveProps() and then setState there, so that in IssueBox I can continue using this.props thus in turn updating it.

import React, { Component } from "react";
  import IssueBox from "./issuebox.js";
  import "./App.css";

  class App extends Component {
    constructor(props) {
      super(props);

      this.state = {
        isLoaded: false,
        email: [],
        counter: 0,
        title: "Test run"
      };
    }

    componentDidMount() {

      fetch(
        "https://s3-us-west-2.amazonaws.com/s.cdpn.io/311743/dummy-emails.json"
      )
        .then(res => res.json())
        .then(result => {
          const emails = result.data;
          console.log("resutl state: ", emails);
          let id = 0;
          for (const email of emails) {
            email.id = id++;
            email.verified = 'False'
          }
          this.setState({
            isLoaded: true,
            emails: emails
          });
        });
    }
    render() {
      //console.log(this.state.email);
      return (
        <div className="App">
          <div>
            <IssueBox emails={this.state.email} />
          </div>
        </div>
      );
    }
  }


  //issuebox.js

  import React, { Component } from "react";

  class IssueBox extends Component {
    constructor(args) {
      super(args);

      const emails = this.props.emails;
      console.log("inner props: ", emails);
      let id = 0;
      for (const email of emails) {
        email.id = id++;
      }

      this.state = {
        selectedEmailId: 0,
        currentSection: "inbox",
        emails
      };
    }

//...copy and pase from codepen

setSidebarSection(section) {
  let selectedEmailId = this.state.selectedEmailId;
  if (section !== this.state.currentSection) {
    selectedEmailId = "";
  }

  this.setState({
    currentSection: section,
    selectedEmailId
  });
}

componentWillReceiveProps(newProps) {
  // Assign unique IDs to the emails

  this.setState({ emails: newProps.data });
}

render() {
  const currentEmail = this.state.emails.find(
    x => x.id === this.state.selectedEmailId
  );
  return (
    <div>
      <Sidebar
        emails={this.props.emails}
        setSidebarSection={section => {
          this.setSidebarSection(section);
        }}
      />
    )}

  ///.....copy and pase from codepen

Solution

  • The error is being caused by this line in componentWillReceiveProps():

    this.setState({ emails: newProps.data });

    The emails are coming in on a property called emails so that line should be:

    this.setState({ emails: newProps.emails });

    That being said, componentWillReceiveProps() gets called more frequently than you might expect. I recommend that you add the id's to the emails within componentDidMount() of App so they come into IssueBox ready to use. This means that App is keeping the emails in its state and simply passing them to IssueBox as props, so you can remove emails from the state in IssueBox and just use the emails that come in through the props everywhere within IssueBox (similar to how the other components use emails coming in on their props and don't keep them in their own local state).