做者 | Daishi Kato
译者 | 王文刚
编辑 | Yoniereact
React useContext 使用起来很是方便,它能够访问定义 DOM 树中多个组件的全局状态或共享状态。
可是,useContext 不是专为全局状态设计的,而且有一个警告:对上下文值的任何更改都会多播,致使全部 useContext 从新渲染组件。
这篇文章展现了一些关于问题的示例代码以及具备 state 使用跟踪的解决方案。git
咱们以人为对象来举例说明。github
const initialState = { firstName: 'Harry', familyName: 'Potter', };
咱们使用上下文和 local state。redux
const PersonContext = createContext(null); const PersonProvider = ({ children }) => { const [person, setPerson] = useState(initialState); return ( <PersonContext.Provider value={[person, setPerson]}> {children} </PersonContext.Provider> ); };
最后,这是一个显示人物名字的组件。ide
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 组件像这样更改。spa
const DisplayFirstName = () => { const [person] = useTracked(); return ( <div>First Name: {person.firstName}</div> ); };
注意这个变化?只有区别是 useTracked()而不是 useContext(...)。
经过这个小的更改,跟踪 DisplayFirstName 中的状态使用状况。如今,即便更新了 family name,只要 first name 未更新,该组件就不会从新渲染。
这是轻松的渲染优化。设计
有些读者可能会认为也能够经过相似 useSelector 的 hooks API 来实现。
这是另外一个使用 useTracked 的例子。code
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
这篇文章重点介绍了如何轻松使用状态跟踪。篇幅限制,咱们并无讨论这些类库的具体实现。简而言之,咱们使用 Proxy API 来跟踪状态使用状况。咱们还在 Context API 中使用未记录的功能来中止广播。若是你对这些细节感兴趣,请查看如上所述的 GitHub 库。