import React, {
useEffect,
useRef,
} from "react";
import { createRoot } from 'react-dom/client';
// export default function Home() {
function Home() {
const log = console.log;
log(`v18 createRoot =\n`, createRoot);
let root = useRef(null);
useEffect(() => {
// v18
console.log(`root =`, root)
console.log(`root.current =`, root.current)
if(!root.current) {
const App = document.getElementById('v18-app');
root.current = createRoot(App);
// JSX
root.current.render(<h1>Develop. Preview. Ship. 🚀 React v18 🆕</h1>);
}
}, []);
return (
<div id="v18-app">...loading</div>
)
};
export default React.memo(Home);
/*
Warning: You are calling ReactDOMClient.createRoot() on a container that has already been passed to createRoot() before.
Instead, call root.render() on the existing root instead if you want to update it.
// Assignments to the 'root' variable from inside React Hook useEffect will be lost after each render.
// To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property.
// Otherwise, you can move this variable directly inside useEffect.eslintreact-hooks/exhaustive-deps
// https://github.com/facebook/react/issues/14920
*/
React Component 性能优化
PureComponent ✅
import React,{PureComponent} from "react";
class Welcome extends React.PureComponent {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
class Mouse extends React.PureComponent {
// Same implementation as above...
}
class MouseTracker extends React.Component {
// Defined as an instance method, `this.renderTheCat` always refers to *same* function when we use it in render
renderTheCat(mouse) {
return <Cat mouse={mouse} />;
}
render() {
return (
<div>
<h1>Move the mouse around!</h1>
<Mouse render={this.renderTheCat} />
</div>
);
}
}
Since shouldComponentUpdate returned false for the subtree rooted at C2, React did not attempt to render C2, and thus didn’t even have to invoke shouldComponentUpdate on C4 and C5.
For C1 and C3, shouldComponentUpdate returned true, so React had to go down to the leaves and check them.
For C6 shouldComponentUpdate returned true, and since the rendered elements weren’t equivalent React had to update the DOM.
The last interesting case is C8.
React had to render this component, but since the React elements it returned were equal to the previously rendered ones, it didn’t have to update the DOM.
Note that React only had to do DOM mutations for C6, which was inevitable.
For C8, it bailed out by comparing the rendered React elements,
and for C2’s subtree and C7, it didn’t even have to compare the elements as we bailed out on shouldComponentUpdate, and render was not called.
import React,{Component} from "react";
class Welcome extends React.Component {
shouldComponentUpdate() {
// 1. 如果 shouldComponentUpdate 返回值是 false,(子组件直接跳过了 👍) 就不需要进行 react element virtual dom 对比了,直接阻止了组件的重新渲染过程 🚀
// 2. 如果 shouldComponentUpdate 返回值是 true, (子组件不能直接跳过,需要一层一层的遍历,重复该过程 👎)
// 2.1 先进行 react element virtual dom 对比,如果组件没有变化,不需要重新渲染组件 ✅
// 2.2 先进行 react element virtual dom 对比,如果组件变化了,需要重新渲染组件 ❌
return false;
}
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
import React from 'react';
import { pure } from 'recompose';
function PercentageStat({ label, score = 0, total = Math.max(1, score) }) {
return (
<div>
<h6>{ label }</h6>
<span>{ Math.round(score / total * 100) }%</span>
</div>
)
}
// Wrap component using the `pure` HOC from recompose
export default pure(PercentageStat);
React.memo
import React, { memo } from 'react';
function PercentageStat({ label, score = 0, total = Math.max(1, score) }) {
return (
<div>
<h6>{ label }</h6>
<span>{ Math.round(score / total * 100) }%</span>
</div>
)
}
// Wrap component using `React.memo()`
export default memo(PercentageStat);
arePropsEqual
import React, { memo } from 'react';
function PercentageStat({ label, score = 0, total = Math.max(1, score) }) {
return (
<div>
<h6>{ label }</h6>
<span>{ Math.round(score / total * 100) }%</span>
</div>
)
}
// 自定义 compare 方法 ✅
function arePropsEqual(prevProps, nextProps) {
return prevProps.label === nextProps.label;
}
// Wrap component using `React.memo()` and pass `arePropsEqual`
export default memo(PercentageStat, arePropsEqual);