Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing multiple value and setter pairs to Context.Provider in React

Tags:

All the documentation and blog posts I've managed to find so far only deals with a single [value, setValue] pair scenario. In my case I would like/need to pass multiple pairs of [value, setValue] variables to a Provider using the useContext hook.

Here is the typical example I setup in 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'));

If you can share any ideas on how pass multiple [value, setValue] pairs to the Provider or an alternative to my problem will be much appreciated

like image 578
Ricardo Sanchez Avatar asked Sep 08 '19 09:09

Ricardo Sanchez


People also ask

How do you pass multiple values in context provider in React?

To pass multiple values in React Context, we can use the Provider API. Also, we can easily consume the context data by utilizing the useContext React Hook. However, it is important to understand the basic syntax and approach behind this. To get a better idea, let us look at a simple example.

Can I have multiple context in React?

To keep context re-rendering fast, React needs to make each context consumer a separate node in the tree. If two or more context values are often used together, you might want to consider creating your own render prop component that provides both.

How do I use multiple useContext?

You can use an aspect of es6 destructuring to rename the diff context object properties right inside your component. Like this: const { user, despatch: setUser } = useContext(UserContext); const { theme, despatch: setTheme } = useContext(ThemeContext); const { state, despatch: setState } = useReducer(reducer);


3 Answers

Context.Provider accepts any value, so you can try passing an object:

<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")); 

Notice that there is a caveat when trying to optimize useless renders (be sure you not just optimizing prematurely): there is no render bailout for Context Consumers.

As for v17, may be change in near future.

like image 51
Dennis Vash Avatar answered Sep 27 '22 19:09

Dennis Vash


To pass in multiple state values to a provider, you just need to create another state object and pass it in.

But inlining these comes with a caveat mentioned in the docs. Since the object (and arrays) in render are created every render, they lose the referential equality and hance any components connected to this context will need to refresh.

To get around this in a functional component, you can use useMemo to memoise the value and refresh only when one of these values change.

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>
    );
}
like image 29
Agney Avatar answered Sep 27 '22 20:09

Agney


You can send values as shown below. I have sent demo1, setdemo1, demo2, and setdemo2. Inside the {{}} inside exportValues.provider It worked for me

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;
like image 29
Soumik Chakraborty Avatar answered Sep 27 '22 21:09

Soumik Chakraborty