Hi everyone, I'm Kasong.
Yesterday a Demo
sent me a 06145bfbc20310, let me explain the reason.
Demo
a look, good guy, the little one is 06145bfbc2032a, the knowledge points are included:
Hooks
's closure problemstate
is 06145bfbc20396 assembled
I believe that if you understand this Demo
, you will have a deeper understanding function components.
Confusing Demo
Demo
contains a button and a list.
<div className="App">
<button onClick={add}>Add</button>
{list.map(val => val)}
</div>
Click the button to call the add
method to insert an item into the list:
let i = 0;
export default function App() {
const [list, setList] = useState([]);
const add = () => {
// ...
};
return (
<div className="App">
<button onClick={add}>Add</button>
{list.map(val => val)}
</div>
);
}
display effect:
Local burning of the brain that calls add
method is to insert a button calls the add method click :
const add = () => {
setList(
list.concat(
<button
key={i}
onClick={add}>
{i++}
</button>
)
);
};
The display effect after clicking the Add
So the question is, what will be the effect after clicking the button with a number (which will call add
method the same as Add button)?
State assembly and closure problems
If you think you will insert a new button:
That would be wrong.
The correct answer is: After clicking the corresponding button, the length list
button corresponding number + 1 , and the number of the last item is largest number before clicking + 1 .
For example, the maximum number before clicking is 6
If you click 0, the length of list
0 + 1 = 1
, and the last item is 6 + 1 = 7
:
If you click 2, the length of list
2 + 1 = 3
, and the last item is 6 + 1 = 7
:
This is the result of two factors:
Hooks
closure problemstate
is 06145bfbc20699 assembled
Cause Analysis
Let's take a look at the add
method:
const add = () => {
setList(
list.concat(
<button
key={i}
onClick={add}>
{i++}
</button>
)
);
};
button
click to call add
, it will be based on add
relevant context ( App
formed closure function), the closure comprising:
- add
- list
- setList
i
belongs to themodule
level, not in the closure
Among them, list
and setList
come from the return value after calling useState
const [list, setList] = useState([]);
A common cognitive errors are: multiple calls useState
returned list
is the same references.
In fact, the useState
returned by list
is calculated based on the following formula:
Base state + update1 + update2 + ... = current state
So it is a brand new object.
If you want to know more about the calculation details ofupdate
andstate
React Technology Revealed
When rendered on the first screen:
App
component for the first timerender
- Create
list = []
<button onClick={add}>Add</button>
depends onadd
to form a closure, and the closure islist = []
Next, click the Add button:
- Call the
add
method, which comes from the closure created byfirst screen rendering
add
process dependentlist
from the same closure, solist = []
<button key={i} onClick={add}>{i++}</button>
depends onadd
to form a closure. Thelist = []
So, for button 0,
Whenever you click, what he actually performs is:
setList(
[].concat(
<button key={i} onClick={add}>{i++}</button>
)
);
So how to fix this problem is also very simple, change setList
to the function form:
// 之前
setList(list.concat(<button key={i} onClick={add}>{i++}</button>));
// 之后
setList(list => list.concat(<button key={i} onClick={add}>{i++}</button>));
list
in the function parameter Hooks
saved in list
, not list
in the closure.
Summarize
Since Hooks
always calculates the new state when the component is render
, this brings a heavier mental burden Hooks
In contrast, using fine-grained update achieve Hooks
(such as VUE
Composition API
) can update the status in real time, and the operation is more intuitive.
In the Hooks
, have you encountered similar headaches?
Welcome to join the human high-quality front-end framework research group , lead the flight
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。