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);