current position:Home>Quietly tell you: the wrong place in react18 document

Quietly tell you: the wrong place in react18 document

2022-04-29 05:25:45calzone

Hello everyone , I'm Carson

React18 The official version has been released for some time , If you upgrade to v18, And still use ReactDOM.render Create an , You will receive the following alarm :

To the effect that :v18 Use createRoot instead of render Create an , If you still use render Create an , Then the behavior of the application will be the same as v17 equally .

React The reason why the team has the confidence to let everyone upgrade to v18, Use createRoot, Because they made a commitment :

To the effect that : If you upgrade to v18, As long as you don't use Concurrent characteristics ( such as useTransition),React Will be consistent with previous versions ( Updates are synchronized 、 Non interruptible )

What this article wants to say today is : In some cases , The above statement is wrong .

Welcome to join Human high-quality front-end framework group , Take flight

Don't say nonsense , Example above

Examples include ab Two states , After rendering for the first time 2 Seconds later, it will trigger ab to update .

Which triggers b The way of updating is special : Click on the simulation , Indirectly trigger b to update :

function App() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);
  const BtnRef = useRef<HTMLButtonElement>(null);

  useEffect(() => {
    setTimeout(() => {
      setA(9000);
      BtnRef.current?.click();
    }, 2000);
  }, []);

  return (
    <div>
      <button ref={BtnRef} onClick={() => setB(1)}>
        b: {b}
      </button>
      {Array(a).fill(0).map((_, i) => {
        return <div key={i}>{a}</div>;
      })}
    </div>
  );
}
Full example address

Now we have two kinds of Mount <App/> The way .

v18 The way before :

const rootElement = document.getElementById("root");

// v18 How to create the application before 
ReactDOM.render(<App/>, rootElement);

v18 How to provide :

const root = ReactDOM.createRoot(rootElement);

// v18 How to create an application 
root.render(
  <App />
);

To see the difference between the two , There are two ways :

  1. turn up setA(9000) The value in , Make the page render more items . The more obvious the Caton is when the page is rendered , The more obvious the difference in rendering order
setTimeout(() => {
  setA(9000);
  BtnRef.current?.click();
}, 2000);
  1. stay react-dom.development.js Of commitRootImpl Break in the method

The method is React The method called when rendering , The order of page rendering can be seen from the break point here .

about ReactDOM.render Created apps , After triggering the update, the rendering order is as follows :

First :

secondly :

about ReactDOM.createRoot Created apps , After triggering the update, the rendering order is as follows :

First :

secondly :

The rendering order has obviously changed , This sum React The statement in the document is contrary .

What are the reasons behind it ?

Update priority , Everywhere

Let's explain... In the example b Why use Trigger onClick event Indirectly trigger updates :

BtnRef.current?.click();

This is because : Updates triggered in different ways are different priority ,onClick Callback The update triggered in is the best , namely Synchronization priority .

So here comes the question ,v18 Don't use concurrency , All updates should not be Sync 、 Non interruptible Well ?

That's true , The update itself is Sync 、 Non interruptible Of . But updates need to be scheduled .

In the example , If the ReactDOM.createRoot Create an , Then the priority when triggering the update is as follows :

setTimeout(() => {
  //  Trigger update , The priority for “ Default priority ”
  setA(9000);
  //  Trigger update , The priority for “ Synchronization priority ”
  BtnRef.current?.click();
}, 2000);

Next React The execution process of is as follows :

  1. a Trigger update , The priority for “ Default priority ”
  2. Dispatch a Update , The priority for “ Default priority ”
  3. b Trigger update , The priority for “ Synchronization priority ”
  4. Dispatch b Update , The priority for “ Synchronization priority ”
  5. At this time, it is found that there are already updates scheduled (a Update ), And lower priority ( Default priority < Synchronization priority )
  6. Cancel a Scheduling of updates , Start scheduling instead b Update
  7. The scheduling process is over , Start syncing 、 Non interruptible execution b Update
  8. b Corresponding updates are rendered to the page
  9. At this time, we found another update (a Update ), Dispatch him
  10. The scheduling process is over , Start syncing 、 Non interruptible execution a Update
  11. a Corresponding updates are rendered to the page

so , Just use ReactDOM.createRoot Create an , that priority The impact will always exist , And The concurrency feature is used Is the difference between the :

  • Only Default priority And Synchronization priority
  • Priority only affects scheduling , Do not interrupt the execution of updates

Old version React The historical burden of

So using ReactDOM.render What is the execution order of the created application ?

Remember a classic ( And it's meaningless ) Of React Interview questions :React Is the update synchronous or asynchronous ?

There are two situations ,a The result of printing is 1 Well ?

//  situation 1
onClick() {
  this.setState({a: 1});
  console.log(a);
}
//  situation 2
onClick() {
  setTimeout(() => {
    this.setState({a: 1});
    console.log(a);
  })
}

among , situation 2 in a The printout is 1.

The reason for this , yes React Early realization The batch Caused by a flaw in , It's not an intentional feature .

When React Use Fiber After architecture reconfiguration , Can completely avoid this flaw . But in order to be consistent with the behavior of the old version , Deliberately achieve this .

therefore , In our example , These two updates will not be affected by priority Influence , But it will be For compatibility with older versions Impact :

setTimeout(() => {
  setA(9000);
  BtnRef.current?.click();
}, 2000);

React The execution process of is as follows :

  1. a Trigger update , Because it is setTimeout Triggered in , Therefore, the subsequent update process will be executed synchronously
  2. a Corresponding updates are rendered to the page
  3. b Trigger update , Because it is setTimeout Triggered in , Therefore, the subsequent update process will be executed synchronously
  4. b Corresponding updates are rendered to the page

summary

React As a maintenance fast 10 Annual framework , Keep the framework behavior consistent after major version updates , It's not easy .

The change of update sequence has little impact on general application .

however , If your app relies on updates The current value in the page Make subsequent judgments , Then you need to upgrade to v18 These subtle changes after .

copyright notice
author[calzone ],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2022/116/202204261057363472.html

Random recommended