RTW*_*RTW 3 reactjs react-hooks
在反应中分享一些全球价值和职能的最佳方法是什么?
现在我有一个ContextProvider,里面都有它们:
<AllContext.Provider
value={{
setProfile, // second function that changes profile object using useState to false or updated value
profileReload, // function that triggers fetch profile object from server
deviceTheme, // object
setDeviceTheme, // second function that changes theme object using useState to false or updated value
clickEvent, // click event
usePopup, // second function of useState that trigers some popup
popup, // Just pass this to usePopup component
windowSize, // manyUpdates on resize (like 30 a sec, but maybe can debounce)
windowScroll // manyUpdates on resize (like 30 a sec, but maybe can debounce)
}}
>
Run Code Online (Sandbox Code Playgroud)
但是就像docs中的 sad一样:因为上下文使用引用标识来确定何时重新渲染,所以当提供者的父级重新渲染时,有些陷阱可能会在使用者中触发意外渲染。例如,以下代码将在提供商每次重新渲染时重新渲染所有使用者,因为始终为值创建新对象:
这不好:
<Provider value={{something: 'something'}}>
Run Code Online (Sandbox Code Playgroud)
还行吧:
this.state = {
value: {something: 'something'},
};
<Provider value={this.state.value}>
Run Code Online (Sandbox Code Playgroud)
我想在将来我可能会多达30个上下文提供者,而且它不是很友好:/
那么如何将这个全局值和函数传递给组件呢?我可以
我在提供程序中使用的示例:
// Resize
const [windowSize, windowSizeSet] = useState({
innerWidth: window.innerWidth,
innerHeight: window.innerHeight
})
// profileReload
const profileReload = async () => {
let profileData = await fetch('/profile')
profileData = await profileData.json()
if (profileData.error)
return usePopup({ type: 'error', message: profileData.error })
if (localStorage.getItem('deviceTheme')) {
setDeviceTheme(JSON.parse(localStorage.getItem('deviceTheme')))
} else if (profileData.theme) {
setDeviceTheme(JSON.parse(JSON.stringify(profileData.theme)))
} else {
setDeviceTheme(settings.defaultTheme)
}
setProfile(profileData)
}
// Click event for menu close if clicked outside somewhere and other
const [clickEvent, setClickEvent] = useState(false)
const handleClick = event => {
setClickEvent(event)
}
// Or in some component user can change theme just like that
setDeviceTheme({color: red})
Run Code Online (Sandbox Code Playgroud)
从性能的角度出发,关于将哪些内容组合在一起的主要考虑是,较少地考虑将哪些内容一起使用,而更多地关注哪些内容一起更改。对于大多数一次(或至少很少)进入上下文的事物,您可以将它们放在一起而没有任何问题。但是,如果某些事情更频繁地混入该更改中,则可能需要将它们分开。
例如,deviceTheme对于给定的用户,我希望它是相当静态的,并且可能被大量组件使用。我想这popup可能在管理您当前是否打开了一个弹出窗口,因此它可能会随着与打开/关闭弹出窗口相关的每项操作而改变。如果popup和deviceTheme捆绑在同一上下文中,则每次popup更改都会导致依赖的所有组件deviceTheme也重新呈现。所以我可能会有一个单独的PopupContext。windowSize并且windowScroll可能会有类似的问题。使用哪种确切的方法可以深入了解领域,但是您可以AppContext针对不经常变化的部分,然后针对更频繁变化的事物提供更具体的上下文。
下面的CodeSandbox演示了useState和useContext之间的交互,其中上下文分为几种不同的方式以及一些按钮来更新上下文中保存的状态。
您可以转到该URL在完整的浏览器窗口中查看结果。我鼓励您首先了解结果的工作方式,然后查看代码并尝试使用它(如果您想了解其他情况)。
这个答案已经很好地解释了如何构建上下文以提高效率。但最终目标是让上下文消费者仅在需要时更新。这取决于具体的情况,最好使用单个上下文还是多个上下文。
在这一点上,这个问题对于大多数全局状态 React 实现来说是常见的,例如 Redux。一个常见的解决方案是仅在需要时使用React.PureComponent,React.memo或shouldComponentUpdatehook使消费者组件更新:
const SomeComponent = memo(({ theme }) => <div>{theme}</div>);
...
<AllContext>
{({ deviceTheme }) => <SomeComponent theme={deviceTheme}/>
</AllContext>
Run Code Online (Sandbox Code Playgroud)
SomeComponent将仅在deviceTheme更新时重新渲染,即使上下文或父组件已更新。这可能是也可能不是可取的。
| 归档时间: |
|
| 查看次数: |
3982 次 |
| 最近记录: |