In class component when we want to pass the object to the value of context provider using react context, we have a way to avoid re-rendering issue. Below are the codes
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
text: "",
contextState: {
count: 0,
increment: this.increment
}
};
}
increment = () => {
this.setState({
contextState: {
...this.state.contextState,
count: this.state.contextState.count + 1
}
});
};
onChange = e => {
const { value, name } = e.target;
this.setState({ [name]: value });
};
render() {
return (
<CountContext.Provider value={this.state.contextState}>
<div style={styles}>
<input name="text" value={this.state.text} onChange={this.onChange} />
<div>Count: {this.state.contextState.count}</div>
<Container1 />
<Container2 />
</div>
</CountContext.Provider>
);
}
}
We put this.state.contextState to value of CountContext.Provider. So when user types anything in input element and will not cause <Container1 />
and <Container2 />
re-rendered. Here is the code sandbox: https://codesandbox.io/s/qqx1jqk8mj?file=/src/index.js:260-1105
I am tring to convert it into hooks. Here is the code sandbox https://codesandbox.io/s/affectionate-gauss-duk64?file=/src/index.js but the counter is not working properly. May I please know which part is wrong? thanks
In your hook component, you just need to use the functional setState approach.
setContextState(prevState=>newState)
In your code: https://codesandbox.io/s/admiring-shtern-g6oll?file=/src/index.js
const [contextState, setContextState] = useState({
count: 0,
increment: () => {
setContextState(prev=>({
...prev,
count: prev.count + 1
}));
}
});
The reason you need to do this is because the state value will never update because of the closure around it. contextState.count
will always remain at 0 because it was the value when the state was originally set (0
), and it won't change.