Reputation: 3968
I noticed something in my code and i just wanted to confirm it here. (using Redux and React)
Let's say i have a button and when you click on it, this function gets called:
onClick={ () => {
updateSomeVar(10);
console.log(someVar);
}}
Where updateValue()
dispatches an action that updates the value of someVar
in the store to be 10.
However, in the following console.log
, it still prints the old value of someVar
, instead of 10
.
Is it because the console.log
runs before the store update triggers a React component re-render and that's why we still see the old value? (after the component re-renders, the value is indeed 10
).
I just thought Redux actions are synchronous, so i expected the console.log
to have the most recent value?
Upvotes: 0
Views: 487
Reputation: 1592
Yes, the state updates are synchronous
by default unless you are using a middleware like thunk
.
What's happening here is that, you are logging the value after the call to updateSomeVar
which re-renders the component.
Each render has its own set of values. Observe this behaviour by using a setTimeout
to the console.log
. It will still print the older value.
This is because state values are used by the component based on the current closure and therefore, the state values will be reflected when the closure is updated (which happens when the component re-renders).
Look at it this way, here is a very simplified implementation of React hooks and state updates.
let React = (function() {
let global = {}; // define a global variable where we store information about the component
let index = 0; // index to keep track of the component's state
function render(Component) {
global.Component = Component;
const instance = Component(); // get the instance of the component
index = 0;
instance.render(); // call the component's render function
global.instance = instance; // store the component's instance for any future calls of the component's functions
return global; // return the global variable
}
function useState(initialState) {
if (!global) {
throw new Error("Need a global");
}
if (!global.hooks) {
global.hooks = []; // this array holds the state of the component
}
const hooks = global.hooks;
const currentState = global.hooks[index] || initialState;
hooks[index] = currentState; // memoize the state for future access
const setState = (function() {
let currentIndex = index; // copy the index so each useState call will have it's own "closed" value over index (currentIndex)
return function(value) {
global.hooks[currentIndex] = value;
render(global.Component); //re-render the component after state change
};
})();
index = index + 1;
return [currentState, setState];
}
return { render, useState, useEffect };
})();
function Component() {
// Component is called at each re-render. index is reset to 0.
const [count, setCount] = React.useState(0);
// hooks: [0], currentIndex: 0, Incremented Index: 1
const [word, setWord] = React.useState("");
// hooks: [0, ''], currentIndex: 1, Incremented Index: 2
const countSetter = () => {
setCount(count + 1);
};
const wordSetter = word => {
setWord(word);
};
function render() {
console.log(`Count is: ${count}, Word is: ${word}`);
}
return { render, countSetter, wordSetter };
}
const global = React.render(Component); // hooks: [ 0, '', [ 0, '' ], [] ]
global.instance.countSetter(); // hooks: [ 1, '', [ 1, '' ], [] ]
global.instance.countSetter(); // hooks: hooks: [ 2, '', [ 2, '' ], [] ]
global.instance.countSetter(); // hooks: [ 3, '', [ 3, '' ], [] ]
global.instance.wordSetter("yooo"); // hooks: [ 3, 'yooo', [ 3, 'yooo' ], [] ]
global.instance.wordSetter("ssup"); // hooks: [ 3, 'yooo', [ 3, 'yooo' ], [] ]
Your console.log
closes over the value of the state variable for that current render therefore, it returns the value owned by that particular render.
By going over the above implementation, when the component re-renders, the index is updated and then and only then, the new value will be available to the component.
Here's the link to the implementation explaining the concept:
Github link: https://github.com/rohitpotato/implement-react-hooks
Upvotes: 1