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

  • inAsynchronous + Dependency scenario 2Why is an effect ignored
  • inHow about asynchrony?, why the asynchronous side effect is only update but not refresh.