Hello everyone, I'm Casson
React18
official version has been released for some time. If you upgrade to v18
and still use ReactDOM.render
to create an application, you will receive the following alarm:
To the effect that: v18
use createRoot
instead render
create the application, if you still use render
create the application, then the application will act Same as v17
.
React
reason why the team has the confidence to let everyone upgrade to v18
and use createRoot
is because they made a promise:
The general idea is: if you upgrade to v18
, as long as you don't use the concurrency feature (such as useTransition
), React
will be the same as the previous version (the update will be synchronous and consistent with the previous version). uninterrupted)
What this article wants to say today is: In some cases, the above statement is wrong.
Welcome to join the human high-quality front-end framework group , with flying
Don't talk nonsense, the above example
There are examples a
, b
two states, for the first time rendering finished 2 seconds will trigger a
, b
update.
Among them, the way of triggering b
update is special: simulated click, indirect trigger b
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 ways to mount <App/>
.
v18
The way before:
const rootElement = document.getElementById("root");
// v18之前创建应用的方式
ReactDOM.render(<App/>, rootElement);
v18
The way provided:
const root = ReactDOM.createRoot(rootElement);
// v18创建应用的方式
root.render(
<App />
);
To see the difference between the two, there are two ways:
- Increase the value in
setA(9000)
to make the page render more items. The more obvious the lag when the page is rendered, the more obvious the difference in rendering order.
setTimeout(() => {
setA(9000);
BtnRef.current?.click();
}, 2000);
-
react-dom.development.js
incommitRootImpl
method of ---b23ac9dbb1bfd11732d11b3a7dc012c7---
This method is React
the method called when rendering, where you can see the order of page rendering by breaking the point.
For applications created by ReactDOM.render
, the rendering sequence after triggering the update is as follows:
first:
Next:
For the application created by ReactDOM.createRoot
, the rendering sequence after triggering the update is as follows:
first:
Next:
The rendering order has obviously changed, which is contrary to what the React
documentation says.
What is the reason behind this?
Update priority, everywhere
First explain why in the following example b
the update is indirectly triggered by triggering the onClick event :
BtnRef.current?.click();
This is because: the updates triggered by different methods have different priorities , and the update triggered in onClick回调
is the highest priority, that is, the synchronization priority .
So here comes the question, v18
does not use the concurrency feature, shouldn't all updates be synchronous and uninterrupted ?
This is true, the update itself is synchronous and uninterruptible . But updates need to be scheduled.
In the example, if the app is created with ReactDOM.createRoot
, the priority when triggering an update is as follows:
setTimeout(() => {
// 触发更新,优先级为“默认优先级”
setA(9000);
// 触发更新,优先级为“同步优先级”
BtnRef.current?.click();
}, 2000);
Next React
The execution flow is as follows:
-
a
Trigger update with priority "default priority" - Schedule
a
with priority "default priority" -
b
Trigger update with priority "sync priority" - Scheduled update of
b
with priority "sync priority" - At this time, it is found that there is already an update scheduled (the update of
a
), and the priority is lower (default priority < synchronization priority) - Cancel the update scheduling of
a
b
instead - The scheduling process ends and the synchronous, uninterruptible execution
b
-
b
corresponding update is rendered into the page - At this time, it is found that there is another update (the update of
a
), schedule him - The scheduling process ends, and the synchronous, uninterruptible execution
a
-
a
corresponding update is rendered into the page
It can be seen that as long as ReactDOM.createRoot
is used to create an application, the impact of priority will always exist. The difference from using the concurrency feature is:
- Only default priority and sync priority
- Priority only affects scheduling and does not interrupt the execution of updates
The historical baggage of older versions of React
So what about the execution order of applications created with ReactDOM.render
?
Remember a classic (and meaningless) React
question: React
update is synchronous or asynchronous?
In the following two cases, a
print result is 1
?
// 情况1
onClick() {
this.setState({a: 1});
console.log(a);
}
// 情况2
onClick() {
setTimeout(() => {
this.setState({a: 1});
console.log(a);
})
}
Among them, in case 2 a
the print result is 1
.
The reason why this happens is because of a React
in the early implementation of 批处理
, not an intentional feature.
When React
uses Fiber
after the architecture is refactored, this flaw can be completely avoided. But in order to be consistent with the behavior of the old version, this is deliberately implemented.
So, in our example, these two updates will not be affected by the priority , but will be affected by the old version for compatibility :
setTimeout(() => {
setA(9000);
BtnRef.current?.click();
}, 2000);
The execution flow of React
is as follows:
-
a
Trigger the update, because it is triggered insetTimeout
, so the subsequent update process will be executed synchronously -
a
corresponding update is rendered into the page -
b
Trigger the update, because it is triggered insetTimeout
, so the subsequent update process will be executed synchronously -
b
corresponding update is rendered into the page
Summarize
React
As a framework that has been maintained for nearly 10 years, it is not easy to keep the framework behavior consistent after major version updates.
Changes in the update order have little effect on general applications.
However, if your application relies on the current value of the updated page to make subsequent judgments, then you need to pay attention to these subtle changes after upgrading to v18
.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。