Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 如何为提供者使用具有多个值的上下文_Reactjs_React Hooks - Fatal编程技术网

Reactjs 如何为提供者使用具有多个值的上下文

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

在react中共享某些全局价值和功能的最佳方式是什么

现在我有了一个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)
  }}
>

你仍然可以合并它们!如果您关心性能,可以更早地创建对象。我不知道您使用的值是否会改变,如果不改变,这很容易:

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>
    )
    }