I have a React class component with the following code (only included the relevant stuff):
class SomePage extends Component {
constructor(props) {
super(props);
this.state = {
stuff: ""
}
}
// NOTE: this.props.data comes from mapStateToProps from below
componentDidMount() {
console.log(this.props.data) // shows up as "undefined"
}
componentDidUpdate(prevProps) {
console.log(this.props.data); // has the data I need
if((prevProps.data !== this.props.data) && this.props.data.part1 && this.props.data.part2) { // LINE A
console.log("inside if statement"); // never entered
this.setState({stuff: this.props.data.part2}); // need to set state here!!
}
}
render () {
return (
{this.state.stuff}
)
}
const mapStateToProps = state => {
return {
data: state.analysisReducer.data;
}
}
export default connect(mapStateToProps, null)(SomePage);
If I change the componentDidUpdate from above to not include prevProps in the if statement, as shown below, then the setState is called infinitely.
componentDidUpdate(prevProps) {
console.log(this.props.data); // has the data I need
if(this.props.data && this.props.data.part1 && this.props.data.part2) { // LINE B - removed the "prevProps.data !=="
this.setState({stuff: this.props.data.part2}); // entered, but called infinitely
}
}
Problem: As shown above, Line A is never entered and the setState in Line B causes an infinite loop.
Goal: I need to call the setState only once, either when I get access this.props.data once its data becomes available or when the this.props.data changes from the its previous state.
How do I do this?
You are not modifing the data props that you are passing so you don't need to put that in components state. You can skip all the state stuff and just use the props that you are passing.
// Added after comment You are still not editing the data passed from props, but here is an example of how to do what you want with a functional component.
import { useEffect, useState } from "react";
export default function App() {
const [input, setInput] = useState('');
return (
<div className="App">
<h1>Hello</h1>
<input type='text' value={input} onChange={(e) => setInput(e.target.value)} />
<Page data={{ part2: input }} />
</div>
);
}
const Page = (props) => {
const [state, setState] = useState({});
useEffect(() => {
console.log("useEffect");
setState({
...state,
stuff: props.data.part2
});
}, [props.data.part2]);
return <div>{state.stuff}</div>;
};
Codesandbox: https://codesandbox.io/s/adoring-varahamihira-bgqpby