score:9

Accepted answer

The React Context is a mechanism for passing data through a React node tree without having to pass the props manually. The use of createContext creates a reference for a data structure within React's ecosystem that exposes a given data structure to the children nodes.

Context.Provider on the other hand provides a value to consuming components that are children nodes of the Provider. There are a few caveats to remember - whenever the properties of the value your provider is changing, it will trigger a re-render in all of its subscribers - it's descendants. The provider itself is not a hook, therefore when using hooks to generate values, you must re-render the provider with the new values set.


There are several things in your code that need to be addressed:

  1. Using useState in a Context.Provider,
  2. Returning the result of useState as the provider value, and
  3. The structure of data provided as the value to provider

Using useState in a Context.Provider

When consuming the result of useState within a react Context, you have to be aware of the implications of consumption in descendants, and the impact that it will have. React is very good at determining what to re-render and when, and it provides you with control to limit that behavour even more. useState however, is a react Functional Component Hook that will trigger a new render every time the value is updated. There are rules around this, precedence and delays, but you are guaranteed a re-render of whatever Functional Component consumes the useState hook. It's for this reason you want to treat your providers/context objects as pure functions where possible.

Returning the result of useState as the provider value

Within your example, you return the result of the useState call as-is to your context provider. This gives an object structure that React can't properly subscribe to and listen for changes.

The structure of data provided as the value to provider

When using state with your Provider, you need to return as proper JSON to the provider, so that that it can subscribe to value changes, and notify its descendants

Use

const providerValue = {
  expense,
  setExpense,
  clearItems
};
<ExpenseContext.Provider value={providerValue}/>

Instead of:

<ExpenseContext.Provider value = {
  [expense, setExpense],
  clearItems
} .../>

The object structure that you're providing the context provider is invalid. See example codepen.

Check out this great example on dev.to for useState with Context

score:3

How I said in the comment you're very close, you pass functions, objects and values the same way

  const [expenses, setExpenses] = useState([]);
  const clearItems = () => {
    setExpenses([]);
  };
  const value = { expenses, setExpenses, clearItems };

Here is a working example

https://codesandbox.io/s/silent-worker-yfhbm?file=/src/App.js


Related Query

More Query from same tag