Home > Blockchain >  state is undefined when using useContext but not undefined in the provider
state is undefined when using useContext but not undefined in the provider

Time:06-13

I'm trying to experiment creating a generic reusable Provider component, but for some reason when using state from useContext is coming back as undefined. In the provider itself state is not undefined, i can see the initial state.

Provider itself

import React, { useReducer, createContext } from 'react';

export const defaultContext = (context) => {
  let BaseContext = context;
  if (!context) {
    console.log('is this gettinged caled');
    BaseContext = createContext({});
  }
  console.log('BaseContext', BaseContext);
  return {
    BaseContext,
  };
};

function useGenericProvider(reducer, initState, context?) {
  const { BaseContext } = defaultContext(context ? context : null);
  const [state, dispatch] = useReducer(reducer, initState);

  const OurProvider = React.useMemo(() => { // maybe im doing somethning wrong here
    const myProvider = ({ children }: any) => {
      return (
        <BaseContext.Provider value={{ state, dispatch }}>
          {children}
        </BaseContext.Provider>
      );
    };
    return myProvider;
  }, []);

  return {
    OurProvider,
  };
}
export { useGenericProvider };

How the context is being used..

Child.tsx

import React, { useContext } from 'react';
import { defaultContext } from './useGenericReducer';

const Child = () => {
  const { BaseContext } = defaultContext(null);
  const {state, dispatch} = useContext(BaseContext);
  console.log('state *******', BaseContext);
  return (
    <div>
      <div>{state}</div>
    </div>
  );
};

export default Child;

Parent.tsx

import React, { useReducer, useState } from 'react';
import { useGenericProvider } from './useGenericReducer';
import { render } from 'react-dom';
import MainApp from './MainApp';
import './style.css';
import Child from './Child';

interface IinitState {
  count: number;
}

const App: React.FC = () => {
  const initState: IinitState = {
    count: 0,
  };
  function reducer(state: IinitState, action: any) {
    switch (action) {
      case 'ADD':
        return {
          ...state,
          count: state.count   1,
        };
      case 'SUB':
        return {
          ...state,
          count: state.count - 1,
        };
      default:
        return state;
    }
  }

  const { OurProvider } = useGenericProvider(reducer, initState);
  return (
    <OurProvider>
      <Child />
    </OurProvider>
  );
};

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

Reproducible example: https://stackblitz.com/edit/xxtt-react-usereducer-geph38?file=Child.tsx

CodePudding user response:

defaultContext was called more than once and created new context each time. To fix that, put createContext outside of the defaultContext body

let myContext = createContext({});

export const defaultContext = (context) => {
  let BaseContext = context;
  if (!context) {
    console.log('is this gettinged caled');
    BaseContext = myContext;
  }
  console.log('BaseContext', BaseContext);
  return {
    BaseContext,
  };

};

If you need generic context function, just create an object with contexts

const myContext = { myFirstContext: .... }
  • Related