I searched a lot before asking but can't seem to find a solution that works with me.
I have a function that I need to be called after the state is set to the new value.
const onClickCallback = () => {
setState(..., setCallback())
}
const setCallback = () => {
console.log(State) // this prints the old State value
if(State === something){
....
}
}
Eventhough the function is being called as the setState callback, it still gets the older value.
I'm not sure if the problem is from my end or it's just not possible..
CodePudding user response:
Unlike class component's this.setState
, function component's useState
state updater function doesn't take a second callback argument to be called after any state update.
What you are doing is enqueueing a state update and passing extraneous arguments, one of which is a function that you are immediately invoking, and passing any return value to setState
, which will be ignored.
setState(..., setCallback()) // setCallback invoked and result passed
Use an useEffect
hook with a dependency on the state to log any state updates.
const onClickCallback = () => {
setState(...);
};
React.useEffect(() => {
console.log(State) // this prints the updated state value
if(state === something){
....
}
}, [state, /* add other dependencies here */]);
useEffect
with dependency array acts as an equivalent to componentDidMount
and componentDidUpdate
. It's the componentDidUpdate
lifecycle being used above to "react" to the state update and trigger a side-effect.
CodePudding user response:
First
This matter has nothing to do with React, your approach would have caused the setCallback()
function to be executed first.
I edit your code and demo result :
const onClickCallback = () => {
// Here will run setCallback function before setState function.
setState('...', setCallback())
}
const setCallback = () => {
console.info('run setCallback')
}
const setState = () => {
console.info('run setState')
}
onClickCallback()
Second
Answer your question, you can use useEffect
to achieve your goals.
Simple example:
const {useState, useEffect} = React;
const DemoComponent = (props) => {
const [state, setState] = useState('initialState')
useEffect(() => {
if (state === 'something') {
console.info('state:' state)
}
}, [state])
const onClickCallback = () => {
setState('something')
}
return (
<div>
<button onClick={onClickCallback}>Click</button>
</div>
);
}
ReactDOM.render(
<DemoComponent />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>