在React中向Context.Provider传递多个值和setter对

38

到目前为止,我找到的所有文档和博客文章都只处理单个[value, setValue]对的情况。在我的情况下,我需要使用useContext钩子向Provider传递多个[value, setValue]变量对。

以下是我在CodePen中设置的典型示例: https://codepen.io/nardove/pen/XWrZRoE?editors=0011

const App = () => {
    return(
        <div>
            <MyProvider>
                <ComponentA />
            </MyProvider>
        </div>
    );
}

const MyContext = React.createContext();
const MyProvider = (props) => {
    const [value, setValue] = React.useState("foo");
    return(
        <MyContext.Provider value={[value, setValue]}>
            {props.children}
        </MyContext.Provider>
    );
}

const ComponentA = () => {
const [value, setValue] = React.useContext(MyContext);
    return(
        <div>
            <h1>
                The value is: {value}
            </h1>
        </div>
    );
}

ReactDOM.render(<App /> , document.getElementById('app'));

如果您有任何关于如何将多个[value, setValue]对传递给Provider的想法,或者有其他解决我的问题的替代方法,将不胜感激


请尝试使用 useReducer 而不是 useState - Andy
4个回答

70

Context.Provider可以接受任何值,因此您可以尝试传递一个对象:

<MyContext.Provider
  value={{ value: [value, setValue], value2: [value2, setValue2] }}
>
  {props.children}
</MyContext.Provider>;

const App = () => {
  return (
    <MyProvider>
      <ComponentA />
    </MyProvider>
  );
};

const MyContext = React.createContext();

const MyProvider = props => {
  const [value, setValue] = React.useState("foo");
  const [value2, setValue2] = React.useState("goo");

  return (
    <MyContext.Provider
      value={{ value: [value, setValue], value2: [value2, setValue2] }}
    >
      {props.children}
    </MyContext.Provider>
  );
};

const ComponentA = () => {
  const { value, value2 } = React.useContext(MyContext);
  const [stateValue, setStateValue] = value;
  const [stateValue2, setStateValue2] = value2;

  return (
    <div>
      <h1>The value is: {stateValue}</h1>
      <h1>The value2 is: {stateValue2}</h1>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("app"));

请注意,在尝试优化无用的渲染时有一个警告(确保你不仅仅是过早优化):对于上下文消费者,没有渲染撤销
至于v17版本,可能会在不久的将来发生变化。

谢谢!运行得很好,现在进入下一个 ;) - Ricardo Sanchez
3
我在这个问题上卡了一整天,你不知道这帮了我多大的忙。 - WISERDIVISOR
我无法将useState的setter添加到我的context中。初始化出现错误,因为hooks不能在组件外使用。TypeError:未定义的对象(评估'_useContext.value1')。TypeError:setInnerModalType不是一个函数。(在“setInnerModalType('request')”中,“setInnerModalType”未定义) - wly185
@wly185 请开一个单独的问题,我们需要更多的上下文。 - Dennis Vash
为什么这段代码无法正常工作?<MyContext.Provider value={{ value1: [value1, setValue1], value2: [value2, setValue2] }} > - Kaustubh Dwivedi
什么没有起作用?需要比这更多的上下文。 - Dennis Vash

12

要向提供程序传递多个状态值,您只需要创建另一个状态对象并将其传递即可。

但是在文档中提到的一个注意事项是:内联这些对象(和数组)会导致它们在每次渲染时被重新创建,从而失去了引用相等性,因此与此上下文相关联的任何组件都需要刷新。

为了解决这个问题,在函数组件中,您可以使用useMemo来记忆该值,并仅在这些值之一更改时才刷新。

const MyContext = React.createContext();
const MyProvider = (props) => {
    const [valueA, setValueA] = React.useState("foo");
    const [valueB, setValueB] = React.useState("bar");
    const providerValue = React.useMemo(() => ({
        valueA, setValueA,
        valueB, setValueB,
    }), [valueA, valueB]);
    return(
        <MyContext.Provider value={providerValue}>
            {props.children}
        </MyContext.Provider>
    );
}

我收到了一个错误,该值“不可分配给类型'null'”。 - gaitat
useMemo 用于避免任何父组件重新渲染时生成新的上下文实例。查看更多 - Agney
1
对于任何想要记录用于设置上下文对象值的 setter 函数的人,我使用了 useCallback 将函数包装如下。`const updateContextState = useCallback((value: updateContextType) => { setContextState((prevState) => ({ ...prevState, ...value })) }, [])` - Naing
1
并且该函数可以安全地导出如下: `const context = useMemo(() => ({ userID: contextState.userID, updateContextState: updateContextState }), [contextState.userID, updateContextState])return {props.children} ` - Naing

2
创建一个包含Provider组件的内容:
import React, {useState} from "react";
export const Context = React.createContext();

const Provider = props => {
    const [value1, setValue1] = useState("");
    const [value2, setValue2] = useState("");

    return (
        <Context.Provider
            value={{ value1, setValue1, value2, setValue2 }}
        >
            {props.children}
        </Context.Provider>
    );
};

export default Provider;

在您的应用中:
<Provider>
   <ComponentA/>
</Provider>

那么在您的ComponentA中:
const { value1, setValue1, value2, setValue2} = useContext(Context);

现在您可以使用每个值或设置新值。

1
您可以按照以下方式发送值。我已经发送了demo1、setdemo1、demo2和setdemo2。在exportValues.provider中的{{}}内部,它对我起作用了。
import {View, Text} from 'react-native';
import React, {createContext, useState} from 'react';

export const exportValues = createContext();

const ContextTab = ({children}) => {
  const [demo1, setdemo1] = useState([]);
  const [demo2, setdemo2] = useState([]);
  return (
    <exportValues.Provider
      value={{demo1, setdemo1,demo2, setdemo2}}>
      {children}
    </exportValues.Provider>
  );
};

export default ContextTab;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接