While I was studying react hooks, I saw an example of useState function that made of vanilla javascript.
function useState(initVal) {
let _val = initVal
const state = _val
const setState = newVal => {
_val = newVal
}
return [state, setState]
}
const [count, setCount] = useState(1)
console.log(count) // 1
setCount(2)
console.log(count) // 1
Although I declared state as variable, when setState function calls with newValue, the count does not change.
However when the state changes variable to function like below,
function useState(initVal) {
let _val = initVal
const state = () => _val
const setState = newVal => {
_val = newVal
}
return [state, setState]
}
const [count, setCount] = useState(1)
console.log(count()) // 1
setCount(2)
console.log(count()) // 2
the count starts to change.
Is this happening because whenever count function calls, it references changed value of _val by setState function using closure? and How can I explain how react hooks work using closure in javascript?
CodePudding user response:
Although I declared state as variable
Actually, you didn't. You declared it as a const.
The first returns the value of a variable. Plain and simple. It happens to be 1
. The value is copied, you cannot change it. (Obviously you can change what count is set to, but you cannot change 1
).
The second returns a function. That function forms a closure over _val
. _val
isn't evaluated until count()
is called. Each time it's called, it gets the value of _val
and returns it.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
CodePudding user response:
Because you are rebinding it on this line
const state = _val
State becomes a constant frozen with initial value
return [_val, setState]
Change it to this and you will get what you would have expected
CodePudding user response:
When you destructure, you are getting new, distinct variables with copies of the data.
// simple explanation
const list = ['dog'];
const [animal] = list;
console.info(animal); // dog
// change the original
list[0] = 'cat';
// output
console.info(list[0], animal); // cat, dog
Even if you refactor as below to use let
and update correctly, you will not get the original value as there is no reference to it.
function useState(initVal) {
let state = initVal
const setState = newVal => {
state = newVal;
}
return [state, setState];
}
const [count, setCount] = useState(1);
console.log(count); // 1
setCount(2);
console.log(count); // 1
// simple explanation
const list = ['dog'];
const [animal] = list;
console.info(animal);;
list[0] = 'cat';
console.info(list[0], animal);