React Hooks are not magic, they are arrays.
The Preview in codesandbox – >
preface
React Hooks are a new feature introduced in React V16 in 2019 by the Facebook development team. Instead of class components, they see function components as a better fit for front-end UI development and the future direction of React. Use of state and side effects in function components is a problem that needs to be solved. React Hooks are the result of this trend.
1. Closure functions
Write a function called useState that forms a closure inside the function. You can set local variables inside the closure using setState and get the latest state value _val inside the closure by running state().
function useState<T> (initVal: T) : [() = >T, (v: T) = >void] {
let _val = initVal;
let state = () = > _val;
let setState = (newVal: T) = > {
_val = newVal;
};
return [state, setState];
}
const [count, setCount] = useState<number> (1);
console.log(count()); / / - > 1
setCount(2);
console.log(count()); / / - > 2
Copy the code
Running the code above, you can see that the console prints 1 and 2 successively.
2. As a method of React
Function useState() generates a React object using the immediately executed function, puts function useState() into it and returns it:
const React = (() = > {
function useState<T> (initVal: T) : [() = >T, (v: T) = >void] {
let _val = initVal;
let state = () = > _val;
let setState = (newVal: T) = > {
_val = newVal;
};
return [state, setState];
}
return {useState}
})();
const [count, setCount] = React.useState<number> (1);
console.log(count()); / / - > 1
setCount(2);
console.log(count()); / / - > 2
Copy the code
3. Hand-write Component rendering
Manually implement a react. render that prints count and simulates rendering on the console.
const React = (() = > {
let _val: any;
function useState<T> (initVal: T) :T, (v: T) = >void] {
let state = _val || initVal;
let setState = (newVal: T) = > {
_val = newVal;
};
return [state, setState];
}
function render(Com: () => any) {
let C = Com();
C.render();
return C;
}
return{ useState, render }; }) ();function Component() {
const [count, setCount] = React.useState<number> (1);
return {
render: () = > {
console.log(count);
},
click: () = > {
setCount(count + 1); }}; }var app = React.render(Component); / / = > 1
app.click();
var app = React.render(Component); / / = > 2
Copy the code
4. Multiple useState
When we need to use more than one useState, we find that the print is confusing because multiple USestates share the same variable let _val; That’s obviously not what we want.
const React = (() = > {
let _val: any;
function useState<T> (initVal: T) :T, (v: T) = >void] {
let state = _val || initVal;
let setState = (newVal: T) = > {
_val = newVal;
};
return [state, setState];
}
function render(Com: () => any) {
let C = Com();
C.render();
return C;
}
return{ useState, render }; }) ();function Component() {
const [count, setCount] = React.useState<number> (1);
const [text, setText] = React.useState<string> ("React");
return {
render: () = > {
console.log({ count, text });
},
click: () = > {
setCount(count + 1);
},
type: (word: string) = >{ setText(word); }}; }var app = React.render(Component); // => {count: 1, text: "React"}
app.click();
var app = React.render(Component); // => {count: 2, text: 2}
app.type("Vue");
app.type("Vue");
var app = React.render(Component); // => {count: "Vue", text: "Vue"}
Copy the code
5. Use arrays to store state
Use arrays to stably store the state of multiple Usestates, restoring the array subscript to 0 each time the component renders
const React = (() = > {
let hooks: any[] = [];
let idx = 0;
function useState<T> (initVal: T) :T, (v: T) = >void] {
let state = hooks[idx] || initVal;
let _idx = idx;
let setState = (newVal: T) = > {
hooks[_idx] = newVal;
console.log(`hooks[${_idx}] `, newVal);
};
idx++;
return [state, setState];
}
function render(Com: () => any) {
idx = 0;
let C = Com();
C.render();
return C;
}
return{ useState, render }; }) ();function Component() {
const [count, setCount] = React.useState<number> (1);
const [text, setText] = React.useState<string> ("React");
return {
render: () = > {
console.log({ count, text });
},
click: () = > {
setCount(count + 1);
},
type: (word: string) = >{ setText(word); }}; }var app = React.render(Component); // => {count: 1, text: "React"}
app.click(); // => hooks[0] 2
var app = React.render(Component); // => {count: 2, text: 2}
app.type("Vue"); // => hooks[1] Vue
app.type("Vue"); // => hooks[1] Vue
app.click(); // => hooks[0] 3
app.type("Angular"); // => hooks[1] Angular
var app = React.render(Component); // => {count: 3, text: "Angular"}
Copy the code
conclusion
This article uses a separation of concerns approach to describe how useState allows multiple states to coexist and access stably in components through closures and array traversal. The React Diff and React. Render DOM rendering details are shielded from the demo code, and console.log() is used to brush through the process.
Because React Hooks are implemented using closures and array traversal, use the following rules:
- Do not call hooks in loops, conditions, or nested functions;
- Call Hook only in the React function component;
The resources
[1] How do React hooks really work Under The Hood ? By Engineers.SG – Youtube