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: .... }