我以前没怎么在意,props.children 和直接组件.jsx 来渲染页面的差异性
下面例子不会重复渲染 !
- 当点击
Click组件按钮时,count增加,<Clicker />组件重新渲染,同时子组件Render并不会重新渲染 - 我们还是借用了children 的机制,直接渲染,那么在父组件当中就没有 Ract.createElement(Son) 这个api的执行,因此就不会造成重复的渲染!
- 里面的原理有
diff算法,fiber节点
function App() {
return (
<div className="app">
<Click>
<Render />
</Click>
</div>
);
}
function Click({ children }) {
const [count, setCount] = useState(0);
return (
<div className="click">
<h2>{count}</h2>
<button onClick={() => setCount(count + 1)}>+++</button>
{children}
</div>
);
}
function Render() {
const count = React.useRef(0);
React.useEffect(() => {
console.log("component rendered", count.current++);
});
return <div className="render"><p>sub</p></div>;
}
- 他的前后
props永远是相等的,一个节点更新前后props相等,且该节点没有更新,并且其子树中也没有更新,这种情况下以该节点为根的fiber子树的reconciliation过程就会到此为止停止diff <Render />不是<Click>的子组件,它是App的子组件,对于<Click>来说,<Render />是他的一个属性props.children。所以<Render />是否re-render取决于App,而App没有更新- Render函数中是以props.children的形式体现出来的,而App渲染时,其props并未变化,相应的props.children,同样没有变化,所以不会重新渲染。
下面例子会重复渲染 !
function App() {
const [count, setCount] = useState(0);
return (
<div>
<h2>{count}</h2>
<button onClick={() => setCount(count + 1)}>+++</button>
<Render />
</div>
);
}
function Render() {
const count = React.useRef(0);
useEffect(() => {
console.log("component rendered", count.current++);
});
return ( <div className="Render"><p>sub</p></div> )
}
Render>终会编译成 React.createElement(Render, null) 这个形式,注定要重复渲染这个子组件, 返回结果是一个ReactElement全新的引用,而它里面的props也是一个全新的对象- 由于
Render的JSX元素在App中被重新创建,所以他的props就不相等了 - 如果不想让他重复渲染,可以将
<Render>这个组件包裹在memo中这时候比较他更新前后的props是否变更,就会转换为对其中的每个属性进行浅比较 - 状态维护在App中,
<Render />是App的子组件,所以会刷新
结语
前端react QQ群:
788023830----React/Redux - 地下老英雄前端交流QQ群:
249620372----FRONT-END-JS前端(我们的宗旨是,为了加班,为了秃顶……,仰望大佬),希望小伙伴们加群一起学习