Home > Net >  Where to fetchRecords in React - componentDidMount or onComponentDidUpdate or else where?
Where to fetchRecords in React - componentDidMount or onComponentDidUpdate or else where?

Time:09-30

I am attempting to get some records, from my redux store in a component. However, I am only trying to fetch records that belong to the currently logged-in user, which I get access to through my mapStateToProps function. -- ie, I am calling fetchRuns(userId)

I can't seem to figure out how or where to make this call. If I make the call in componentDidMount, userId is still null at this point. If I make the call in componentDidUpdate, I get an infinite loop, because my component updates when it returns. From my research, it sounds like I might need to keep track of another piece of state in componentDidUpdate that lets me know if I should make the call... I haven't been able to figure out how to do that.

My code

import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { fetchRuns } from "../actions";
import RunCell from "./RunCell";

class Runs extends React.Component {
  componentDidUpdate() {
    // TODO: BUG - go to run , refresh, hit cancel, all other runs are missing
    this.props.fetchRuns(this.props.userId);
  }

  renderRuns() {
    //Show runs in reverse chronological order
    const sortedRuns = this.props.runs.sort(
      (a, b) => new Date(b.runDate) - new Date(a.runDate)
    );

    return sortedRuns.map((run) => {
      return <RunCell {...run} key={run.id} />;
    });
  }

  render() {
    if (this.props.runs) {
      return (
        <div className="ui container">
          <div className="ui secondary pointing menu">
            <h3>Your Training Log</h3>
            <div className="right menu">
              <Link className="ui button right" to="/runs/add">
                Add Run
              </Link>
            </div>
          </div>
          <div className="ui">{this.renderRuns()}</div>
        </div>
      );
    } else {
      return <div>Loading runs...</div>;
    }
  }
}

function mapStateToProps(state) {
  return { runs: Object.values(state.runs), userId: state.auth.userId };
}

export default connect(mapStateToProps, { fetchRuns })(Runs);

CodePudding user response:

You are close to the solution, you just need to compare the new userId prop with the old one to prevent the infinite loop:

import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { fetchRuns } from "../actions";
import RunCell from "./RunCell";

class Runs extends React.Component {
  componentDidUpdate(prevProps) {
    if(prevProps.userId !== this.props.userId){ // <=== In order to prevent infinite loop add this comparison
       this.props.fetchRuns(this.props.userId);
    }
  }

  componentDidMount() {
    if(this.props.userId){ // <=== fetch your data inside this methode
      this.props.fetchRuns(this.props.userId);
   }
  }

  renderRuns() {
    //Show runs in reverse chronological order
    const sortedRuns = this.props.runs.sort(
      (a, b) => new Date(b.runDate) - new Date(a.runDate)
    );

    return sortedRuns.map((run) => {
      return <RunCell {...run} key={run.id} />;
    });
  }

  render() {
    if (this.props.runs) {
      return (
        <div className="ui container">
          <div className="ui secondary pointing menu">
            <h3>Your Training Log</h3>
            <div className="right menu">
              <Link className="ui button right" to="/runs/add">
                Add Run
              </Link>
            </div>
          </div>
          <div className="ui">{this.renderRuns()}</div>
        </div>
      );
    } else {
      return <div>Loading runs...</div>;
    }
  }
}

function mapStateToProps(state) {
  return { runs: Object.values(state.runs), userId: state.auth.userId };
}

function mapDispatchToProps(dispatch) {
  return {
    fetchRuns: (userId) => dispatch(fetchRuns(userId))
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Runs);
  • Related