Reactjs 如何为提供者使用具有多个值的上下文
在react中共享某些全局价值和功能的最佳方式是什么 现在我有了一个ContextProvider,其中包含了所有内容:Reactjs 如何为提供者使用具有多个值的上下文,reactjs,react-hooks,Reactjs,React Hooks,在react中共享某些全局价值和功能的最佳方式是什么 现在我有了一个ContextProvider,其中包含了所有内容: <AllContext.Provider value={{ setProfile, // second function that changes profile object using useState to false or updated value profileReload, // function that triggers fetch
<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)
}}
>
你仍然可以合并它们!如果您关心性能,可以更早地创建对象。我不知道您使用的值是否会改变,如果不改变,这很容易:
state = {
allContextValue: {
setProfile,
profileReload,
deviceTheme,
setDeviceTheme,
clickEvent,
usePopup,
popup,
windowSize
}
}
render() {
return <AllContext.Provider value={this.state.allContextValue}>...</AllContext>;
}
这既有性能,也相对容易:)
拆分这些内容可能会加快一点速度,但我只会在您发现它实际上很慢时才这么做,并且只会在您的上下文中有很多消费者的部分进行拆分
尽管如此,如果您的价值没有太大变化,那真的没什么好担心的。从性能的角度来看,将哪些内容组合在一起的主要考虑因素不是哪些内容一起使用,而是哪些内容一起变化。对于大多数情况下只设置一次上下文(或者至少很少设置)的内容,您可能可以将它们放在一起而不产生任何问题。但是,如果有一些东西更频繁地混合在这种变化中,那么将它们分离出来可能是值得的
例如,我希望deviceTheme
对于给定用户来说是相当静态的,并且可能被大量组件使用。我猜,popup
可能是在管理当前是否打开了一个弹出窗口,因此它可能会随着与打开/关闭弹出窗口相关的每个操作而改变。如果popup
和deviceTheme
捆绑在同一上下文中,则每次popup
更改都会导致依赖deviceTheme
的所有组件也重新渲染。所以我可能会有一个单独的PopupContext
WindowsSize
和windowScroll
可能会出现类似问题。使用什么样的确切方法会深入到意见领域,但对于不经常变化的部分,可以使用AppContext
,然后对于变化更频繁的部分,可以使用更具体的上下文
下面的CodeSandbox演示了useState和useContext之间的交互,上下文以几种不同的方式划分,并使用一些按钮来更新上下文中保存的状态
您可以转到以在完整的浏览器窗口中查看结果。我鼓励您首先了解结果是如何工作的,然后查看代码,如果您还想了解其他场景,请尝试使用它。已经很好地解释了如何构建上下文以提高效率。但最终目标是使上下文使用者仅在需要时更新。这取决于具体情况,最好是使用单个上下文还是多个上下文
在这一点上,问题对于大多数全局状态响应实现来说是常见的,例如Redux。一种常见的解决方案是仅在需要时使用React.PureComponent
、React.memo
或shouldComponentUpdate
钩子更新消费者组件:
const SomeComponent = memo(({ theme }) => <div>{theme}</div>);
...
<AllContext>
{({ deviceTheme }) => <SomeComponent theme={deviceTheme}/>
</AllContext>
constsomecomponent=memo(({theme})=>{theme});
...
{({deviceTheme})=>
<代码>文件组> >代码>只在<代码> DEVICE主题> /COD>更新,即使上下文或父组件被更新。这可能是也可能不是理想的。
< P>赖安的答案是非常棒的,在设计如何构造上下文提供程序层次结构时应该考虑这一点。 我提出了一个解决方案,您可以使用该解决方案使用多个useState
s来更新provider中的多个值
例如:
const TestingContext = createContext()
const TestingComponent = () => {
const {data, setData} = useContext(TestingContext)
const {value1} = data
return (
<div>
{value1} is here
<button onClick={() => setData('value1', 'newline value')}>
Change value 1
</button>
</div>
)
}
const App = () => {
const values = {
value1: 'testing1',
value2: 'testing1',
value3: 'testing1',
value4: 'testing1',
value5: 'testing1',
}
const [data, setData] = useState(values)
const changeValues = (property, value) => {
setData({
...data,
[property]: value
})
}
return (
<TestingContext.Provider value={{data, setData: changeValues}}>
<TestingComponent/>
{/* more components here which want to have access to these values and want to change them*/}
</TestingContext.Provider>
)
}
const TestingContext=createContext()
常量测试组件=()=>{
const{data,setData}=useContext(TestingContext)
常量{value1}=数据
返回(
{value1}在这里
setData('value1','newline value')}>
更改值1
)
}
常量应用=()=>{
常量值={
值1:'测试1',
值2:'测试1',
值3:'测试1',
值4:'测试1',
值5:'测试1',
}
const[data,setData]=useState(值)
常量changeValues=(属性,值)=>{
设置数据({
…数据,
[属性]:值
})
}
返回(
{/*此处有更多组件希望访问这些值并更改它们*/}
)
}
谢谢,现在已经很清楚了!只有一个问题,函数本身算是可变的吗(如果经常使用它作为例子)?像function test(){console.log(1)}-我经常使用它,但它会触发提供者的重新提交程序吗?我已经在我的答案中添加了一个CodeSandbox,这将有助于使它更具体,并允许您试验不同的场景并查看其行为。
state = {
allContextValue: {
setProfile,
profileReload,
deviceTheme,
setDeviceTheme,
clickEvent,
usePopup,
popup,
windowSize
}
}
render() {
return <AllContext.Provider value={this.state.allContextValue}>...</AllContext>;
}
this.setState({
allContextValue: {
...this.state.allContextValue,
usePopup: true,
},
});
const SomeComponent = memo(({ theme }) => <div>{theme}</div>);
...
<AllContext>
{({ deviceTheme }) => <SomeComponent theme={deviceTheme}/>
</AllContext>
const TestingContext = createContext()
const TestingComponent = () => {
const {data, setData} = useContext(TestingContext)
const {value1} = data
return (
<div>
{value1} is here
<button onClick={() => setData('value1', 'newline value')}>
Change value 1
</button>
</div>
)
}
const App = () => {
const values = {
value1: 'testing1',
value2: 'testing1',
value3: 'testing1',
value4: 'testing1',
value5: 'testing1',
}
const [data, setData] = useState(values)
const changeValues = (property, value) => {
setData({
...data,
[property]: value
})
}
return (
<TestingContext.Provider value={{data, setData: changeValues}}>
<TestingComponent/>
{/* more components here which want to have access to these values and want to change them*/}
</TestingContext.Provider>
)
}