轻松渲染优化:使用React Hooks进行state跟踪

Posted 前端之巅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了轻松渲染优化:使用React Hooks进行state跟踪相关的知识,希望对你有一定的参考价值。

作者 | Daishi Kato
译者 | 王文刚
编辑 | Yonie
  介绍  

React useContext 使用起来非常方便,它可以访问定义 DOM 树中多个组件的全局状态或共享状态。

但是,useContext 不是专为全局状态设计的,并且有一个警告:对上下文值的任何更改都会多播,导致所有 useContext 重新渲染组件。

这篇文章展示了一些关于问题的示例代码以及具有 state 使用跟踪的解决方案。

问题定位

我们以人为对象来举例说明。

const initialState = {
firstName: 'Harry',
familyName: 'Potter',
};

我们使用上下文和 local state。

const PersonContext = createContext(null);

const PersonProvider = ({ children }) => {
const [person, setPerson] = useState(initialState);
return (
<PersonContext.Provider value={[person, setPerson]}>
{children}
</PersonContext.Provider>
);
};

最后,这是一个显示人物名字的组件。

const DisplayFirstName = () => {
const [person] = useContext(PersonContext);
return (
<div>First Name: {person.firstName}</div>
);
};

到现在为止还挺好。

但是,问题是当你更新此人的 family name 的同时,它将触发 DisplayFirstName 重新渲染,甚至渲染结果都是相同的。

请注意,这是不是一个真正的问题,直到它成为一个问题。通常情况下,大多数较小的应用程序都可以正常运行,但是一些较大的应用程序会产生性能问题。

解决方案

让我们看看状态使用跟踪如何解决这个问题。

provider 看起来有点不同,但代码基本相同。

const usePerson = () => useState(initialState);
const { Provider, useTracked } = createContainer(usePerson);

const PersonProvider = ({ children }) => (
<Provider>
{children}
</Provider>
);

DisplayFirstName 组件像这样更改。

const DisplayFirstName = () => {
const [person] = useTracked();
return (
<div>First Name: {person.firstName}</div>
);
};

注意这个变化?只有区别是 useTracked()而不是 useContext(...)。

通过这个小的更改,跟踪 DisplayFirstName 中的状态使用情况。现在,即使更新了 family name,只要 first name 未更新,该组件就不会重新渲染。

这是轻松的渲染优化。

高级示例

有些读者可能会认为也可以通过类似 useSelector 的 hooks API 来实现。

这是另一个使用 useTracked 的例子。

const initialState = {
firstName: 'Harry',
familyName: 'Potter',
showFullName: false,
};

假设我们有一个像上面这样的 state ,让我们创建一个带有条件的组件。

const DisplayPersonName = () => {
const [person] = useTracked();
return (
<div>
{person.showFullName ? (
<span>
Full Name: {person.firstName}
<Divider />
{person.familyName}
</span>
) : (
<span>First Name: {person.firstName}</span>
)}
</div>
);
};

此组件将在两个场景中重新渲染:

a)当更新 firstName 或 familyName 时,显示全名。

b)当更新 firstName 时,不显示全名。

使用 useSelector 重现相同的行为并不容易,最终可能会在组件中分开。

使用状态来进行跟踪的项目

有两个项目使用状态来跟踪:

  • https://github.com/dai-shi/reactive-react-redux

  • https://github.com/dai-shi/react-tracked


  结束  

这篇文章重点介绍了如何轻松使用状态跟踪。篇幅限制,我们并没有讨论这些类库的具体实现。简而言之,我们使用 Proxy API 来跟踪状态使用情况。我们还在 Context API 中使用未记录的功能来停止广播。如果你对这些细节感兴趣,请查看如上所述的 GitHub 库。

以上是关于轻松渲染优化:使用React Hooks进行state跟踪的主要内容,如果未能解决你的问题,请参考以下文章

React Hook - Hook规则

P08:useMemo优化React Hooks程序性能

React Hooks究竟是什么呢?

react 16 Hooks渲染流程

新玩具,React v16.7.0-alpha Hooks

使用 React Hooks 重新渲染的次数过多