The cause of
I had an Epiphany. I didn’t know anything about react hooks. Then I wrote a couple of demos based on the rendering logic I knew and printed the log. I don’t know anything. What the hell am I writing?
Locksmith: Do you make a key? Me: I don't deserve it
Do you have a key?
The following code is more, but are brainless simple code, also please follow me according to your understanding, see if it is the same as you understand, I was pressed to the ground to beat a small piece
Let’s start with the synchronization scenario
export default function Effect() { const [name1, updateName1] = useState('name1'); const [name2, updateName2] = useState('name2'); const [name3, updateName3] = useState('name3'); useEffect(() => { console.log('---1---'); updateName1('name1111'); console.log('---4---'); updateName2('name2222'); console.log('---3---'); updateName3('name3333'); } []); console.log('---render---'); return <div style={{ marginTop: '100px' }} className="doc-ui-btns"> <div>name1: {name1}</div>\ <div>name4: {name2}</div> <div>name3: {name3}</div> </div>; }Copy the code
Click to see the results
console.log('---render---');
console.log('---1---');
console.log('---4---');
console.log('---3---');
console.log('---render---');
Copy the code
Let’s take a look at several effects in the synchronization scenario
export default function Effect() { const [name1, updateName1] = useState('name1'); const [name2, updateName2] = useState('name2'); const [name3, updateName3] = useState('name3'); useEffect(() => { console.log('---1---'); updateName1('name1111'); } []); useEffect(() => { console.log('---4---'); updateName2('name2222'); } []); useEffect(() => { console.log('---3---'); updateName3('name3333'); } []); console.log('---render---'); return <div style={{ marginTop: '100px' }} className="doc-ui-btns"> <div>name1: {name1}</div>\ <div>name4: {name2}</div> <div>name3: {name3}</div> </div>; }Copy the code
Click to see the results
console.log('---render---'); console.log('---1---'); console.log('---4---'); console.log('---3---'); console.log('---render---'); Same as in a useEffectCopy the code
Asynchronous scenario 1: Multiple UPDATES in asynchronous functions
export default function Effect() { const [name1, updateName1] = useState('name1'); const [name2, updateName2] = useState('name2'); const [name3, updateName3] = useState('name3'); useEffect(() => { setTimeout(() => { console.log('---1---'); updateName1('name1111'); console.log('---4---'); updateName2('name2222'); console.log('---3---'); updateName3('name3333'); }}, 100), []); console.log('---render---'); return <div style={{ marginTop: '100px' }} className="doc-ui-btns"> <div>name1: {name1}</div>\ <div>name4: {name2}</div> <div>name3: {name3}</div> </div>; }Copy the code
Click to see the results
console.log('---render---'); console.log('---1---'); console.log('---render---'); console.log('---4---'); console.log('---render---'); console.log('---3---'); console.log('---render---'); In an asynchronous scenario, each update triggers render, which is the same as setState in an asynchronous scenarioCopy the code
Does it feel easier? Is this it?
Look backward
Synchronization scenario + Dependency
function Effect() { const [name1, updateName1] = useState('name1'); const [name2, updateName2] = useState('name2'); const [name3, updateName3] = useState('name3'); useEffect(() => { console.log('---1---'); updateName1('name1111'); console.log('---4---'); updateName2('name2222'); console.log('---3---'); updateName3('name3333'); } []); useEffect(() => { console.log('---5---'); updateName2('name2222'); }, [name1]); useEffect(() => { console.log('---6---'); updateName2('name3333'); }, [name3]); console.log('---render---'); return <div style={{ marginTop: '100px' }} className="doc-ui-btns"> <div>name1: {name1}</div> <div>name4: {name2}</div> <div>name3: {name3}</div> </div>; }Copy the code
Click to see the results
console.log('---render---'); console.log('---1---'); console.log('---4---'); console.log('---3---'); console.log('---5---'); console.log('---6---'); console.log('---render---'); console.log('---5---'); console.log('---6---'); console.log('---render---'); You'll notice that steps 5 and 6 are executed twice and refreshed by merging.Copy the code
Asynchronous scenario + dependency
function Effect() { const [name1, updateName1] = useState('name1'); const [name2, updateName2] = useState('name2'); const [name3, updateName3] = useState('name3'); useEffect(() => { console.log('---inner---'); setTimeout(() => { console.log('---1---'); updateName1('name1111'); console.log('---4---'); updateName2('name2222'); console.log('---3---'); updateName3('name3333'); }, 100); } []); useEffect(() => { console.log('---5---'); updateName3('name2222'); }, [name1]); useEffect(() => { console.log('---6---'); updateName2('name3333'); }, [name3]); console.log('---render---'); return <div style={{ marginTop: '100px' }} className="doc-ui-btns"> <div>name1: {name1}</div> <div>name4: {name2}</div> <div>name3: {name3}</div> </div>; }Copy the code
Click to see the results
console.log('---render---');
console.log('---inner---');
console.log('---5---');
console.log('---6---');
console.log('---render---');
console.log('---6---');
console.log('---render---');
console.log('---1---');
console.log('---render---');
console.log('---4---');
console.log('---5---');
console.log('---render---');
console.log('---3---');
console.log('---render---');
console.log('---6---');
console.log('---render---');
Copy the code
Here comes the question, how can 4 and 5 be combined ???? 4 is in async state, according to async scenario 1: multiple updates in async function, the event should render every update, now it is 4/5 merge!!
This effect is dependent on name1 in asynchron, so after update name1, follow the next update, And the side effects are handled after the next update so we have 4 and then 5. If we change the dependency to name2, then 3 and 6 will also be merged after updateName2
Summary: In asynchronous operations, side effects after each update are executed with and after the next update
Asynchronous + dependency scenario 2 has a dependency that is simply ignored and not executed
export default function ToastPage() { const [name1, updateName1] = useState('name1'); const [name2, updateName2] = useState('name2'); const [name3, updateName3] = useState('name3'); const [name4, updateName4] = useState('name4'); UseEffect (() => {console.log('---- first change --'); setTimeout(() => { console.log('---1---'); updateName1('name1111'); console.log('---2---'); updateName4('name1444444'); console.log('---3---'); updateName3('name133333'); }, 100); } []); useEffect(() => { console.log('---4---'); updateName3('name333333'); console.log('---5---'); updateName4('name544444'); }, [name1]); useEffect(() => { console.log('---6---'); updateName2('name344444'); }, [name4]); console.log('---render---'); return <div style={{ marginTop: '100px' }} className="doc-ui-btns"> <div>name1: {name1}</div> <div>name3: {name3}</div> <div>name4: {name4}</div> </div>; }Copy the code
Click to see the results
console.log('---render---'); Console. log('---- first change --'); console.log('---4---'); console.log('---5---'); console.log('---6---'); console.log('---render---'); console.log('---6---'); console.log('---render---'); console.log('---1---'); console.log('---render---'); console.log('---2---'); console.log('---4---'); console.log('---5---'); // The name4 is updated after executing 5, and the name4 is updated after executing 2, but the name4 is updated after executing 6, and the name4 is updated after executing 3. console.log('---render---'); console.log('---3---'); console.log('---render---'); For this process, if console.log('-- 5-- '); updateName4('name544444'); Delete these two lines, and --6-- the dependency executes normally. I don't know why...Copy the code
How about asynchrony?
function ToastPage() { const [name1, updateName1] = useState('name1'); const [name2, updateName2] = useState('name2'); const [name3, updateName3] = useState('name3'); const [name4, updateName4] = useState('name4'); UseEffect (() => {console.log('---- first change --'); setTimeout(() => { console.log('---1---'); updateName1('name1111'); console.log('---2---'); updateName4('name1444444'); console.log('---3---'); updateName3('name133333'); }, 100); } []); UseEffect (() = > {the console. The log (' - change the name1 - '); setTimeout(() => { console.log('---4---'); updateName3('name333333'); console.log('---5---'); updateName4('name544444'); }, 100); }, [name1]); useEffect(() => { console.log('---6---'); updateName2('name344444'); }, [name4]); console.log('---render---'); return <div style={{ marginTop: '100px' }} className="doc-ui-btns"> <div>name1: {name1}</div> <div>name1: {name2}</div> <div>name3: {name3}</div> <div>name4: {name4}</div> </div>; }Copy the code
Click to see the results
console.log('---render---'); Console. log('---- first change --'); Console. log('---- changed name1-- '); console.log('---6---'); console.log('---render---'); Async console.log('-- 1-- '); async console.log('-- 1-- '); console.log('---render---'); console.log('---2---'); // Merge the two, console.log('---- changed name1-- '); // But effect after merge is asynchronous, so just print entry console.log('-- render-- '); // Render console.log('-- 3-- '); Log ('-- 6-- '); console.log('---render---'); // Async console.log('-- 4-- '); // Start processing the second asynchrony, which is actually console.log('-- render-- ') from the first useEffect; // Follow update render once console.log('-- 5-- '); console.log('---render---'); console.log('---6---'); console.log('---render---'); console.log('---4---'); // This is an asynchronous operation with side effects after name1 change, but no render console.log('-- 5-- '); Not renderCopy the code
To summarize
There is a pattern in the execution logic above
- After the first render ends, all effects are executed, and the updates are merged and synchronized
- If a new synchronization effect is triggered in a synchronized effect, the updates are merged
- In asynchrony, each update triggers the render of the page
- In asynchrony, if a side effect occurs with each update, the side effect merges the updates after the next update
- If an asynchronous effect is generated by an asynchronous update, the next asynchronous event will not be triggered until all the current asynchronous updates have finished, resulting in multiple occurrences
Scenes I couldn’t understand
- in
Asynchronous + Dependency scenario 2
Why is an effect ignored - in
How about asynchrony?
, why the asynchronous side effect is only update but not refresh.