React 的核心模式
组合模式(Component Composition)被 Dan Abramov 誉为 2023 最佳的 React 技巧,而且 React 原本也是推荐组合大于继承(Composition over inheritance),可见组合模式在 React 中的重要地位。我们下面就来介绍下组合模式常见的三种好处:
-
减少子组件渲染。
-
减少 Prop Drilling。
-
更佳适合 React Server Component。
减少子组件渲染
我们有下面的例子,当点击 <ParentComponent />
的按钮时,由于 state 的变化,会引起 <ChildComponent />
的重新渲染,如果 <ChildComponent />
是一个耗时的组件,这明显就会造成性能问题。
const ChildComponent = () => {
return <ExpensiveList />;
};
const ParentComponent = () => {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(number + 1)}>{count}</button>
<ChildComponent />
</div>
);
};
如果我们采用组合的模式,将 <ChildComponent />
提升(Lift content up),此时 <ParentComponent />
的渲染就不会引起 <ChildComponent />
的重新渲染。
const ChildComponent = () => {
return <ExpensiveList />;
};
const ParentComponent = ({ children }) => {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(number + 1)}>{number}</button>
{children}
</div>
);
};
const App = () => {
return (
<ParentComponent>
<ChildComponent />
</ParentComponent>
);
};
减少 Prop Drilling
将数据(Props)一级一级向下传是一种常见模式,但是如果传的层数过多、过复杂,使得 Debug 和重构都困难:
const App = () => {
const data = useData();
return (
<ParentComponent data={data} />
);
};
const ParentComponent = ({ data }) => {
return (
<div>
<ChildComponent data={data} />
</div>
);
};
const ChildComponent = ({ data }) => {
return <p>{ data }</p>;
};
我们一般可以使用 React Context、React Hook 或者其他如 Redux 库等等方式来解决。同时我们也可以考虑使用组合模式,这样也能避免 Prop Drilling:
const App = () => {
const data = useData();
return (
<ParentComponent>
<ChildComponent data={data} />
</ParentComponent>
);
};
const ParentComponent = ({ children }) => {
return (
<div>
{children}
</div>
);
};
const ChildComponent = ({ data }) => {
return <p>{ data }</p>;
};
更佳适合 React Server Component
下面代码的问题是,由于 Client Component 不能 import Server Component,所以 <ServerComponent />
只能改为 Client Component,在浏览器渲染,增加发送到浏览器代码量,增加其负担。
const App = () => {
return (
<ClientComponent />
);
};
const ClientComponent = () => {
return (
<div>
{ /* ❌ Client Component 不能 import Server Component */ }
<ServerComponent />
</div>
);
};
const ServerComponent = () => {
return <ExpensiveList />;
};
但是,我们可以采用组合模式,将 Server Component 作为 children 传递给 Client Component,这样 <ServerComponent />
就可以在服务端渲染,减少了浏览器的压力。
const App = () => {
return (
<ClientComponent>
<ServerComponent />
</ClientComponent>
);
};
const ClientComponent = ({ children }) => {
return (
<div>
{children}
</div>
);
};
const ServerComponent = () => {
return <ExpensiveList />;
};
总结
组合模式可以说是 React 最核心设计模式,可以说很多 React 的核心逻辑也是围绕组合模式来设计的,希望本文可以加深大家的理解,以「组合」的方式使用 React。