Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React createContext(null) not allowed with Typescript?

I am trying to set up a React store using useReducer and useContext hooks. The React.createContext(defaultValue) is creating issues with my TS checker. I have tried a few different things, but essentially, I createContext(null) then in the component useReducer() to set state and dispatch, but when I call the Provider and pass the value as {state, dispatch}, it doesn't tells me "Type '{ state: any; dispatch: React.Dispatch; }' is not assignable to type 'null'.

I don't understand this because by the time it errors, I have assigned state and dispatch and the value should no longer be null.

Here is the Context Provider wrapper that I am trying to create.

import React, { createContext, useReducer, FC, Dispatch } from 'react';
import storeReducer, { initialState } from './reducer';
import { Action, State } from './types';
import { isNull } from 'util';

const StoreContext = createContext(null);

const StoreProvider:FC = ({ children }) => {
  const [state, dispatch] = useReducer(storeReducer, initialState);
  const value = {state, dispatch}
  return (
    <StoreContext.Provider value={value}>
      {children}
    </StoreContext.Provider>
  );
};

export { StoreProvider, StoreContext };

export interface IStoreContext {
  dispatch: (action: Action<any>) => {};
  state: State;
}

if I leave it as simply const StoreContext = createContext();, then it complains that defaultValue is not being defined.

The crazy thing is I have lifted this from an old project and had no issues compiling.

like image 643
Nick Burczyk Avatar asked Jul 24 '20 19:07

Nick Burczyk


People also ask

How to use React context in typescript?

Consume the Context with useContext or add a contextType property to class components. The TypeScript types will automatically be infered from the default values or the interface you provided. Continue reading if you want to learn how to use React Context and get a more detailed explanation. As the first step, we need to create a new Context.

How many examples of react createcontext are there?

TypeScript createContext - 30 examples found. These are the top rated real world TypeScript examples of react.createContext extracted from open source projects. You can rate examples to help us improve the quality of examples.

How to get the intended type of a context with null?

When you initialize a context with null, the intended type can't be inferred. You have to give the type of the context explicitly in this case. const StoreContext = createContext< { state: MyStateType, dispatch: Dispact, } | null> (null); I have tried that.

What is the use of createctx in react?

The createCtx function is a generic function that can be used to create contexts for many situations. It simplifies consuming code because checks for undefined are not necessary. That concludes this series of posts on React context with TypeScript.


2 Answers

This may be a case where it is okay to temporarily cast it in order to save yourself a hassle:

interface Store {
  state: MyStateType,
  dispatch: Dispatch,
}

const StoreContext = createContext<Store>({} as Store);

const StoreProvider = ({children}) => {
  const {state, dispatch} = theseAreAlwaysPresent()

  return (
    <StoreContext.Provider value={{state, dispatch}}>
      {children}
    </StoreContext.Provider>
  )
}
... 

like image 58
erikdstock Avatar answered Sep 21 '22 00:09

erikdstock


Since I just made an account to answer this, I can't comment above. Alex Wayne is correct, that is acceptable to Typescript. However, the useContext hook won't really work for this because as far as Typescript is concerned, you may have a null value in that Context.

From original answer... here is our Context in Typescript const StoreContext = createContext<{state: MyStateType, dispatch: Dispatch} | null>(null);

So, we need to create a new hook, let's call it useContextAndErrorIfNull. This would look like:

const useContextAndErrorIfNull = <ItemType>(context: Context<ItemType | null>): ItemType => {
  const contextValue = useContext(context);
  if (contextValue === null) {
    throw Error("Context has not been Provided!");
  }
  return contextValue;
}

Use this hook instead of useContext and it should all work well.

like image 44
Shawn Milligan Avatar answered Sep 22 '22 00:09

Shawn Milligan