I have a few nested Context Providers in my app that look like this
export const LangContext = React.createContext("javascript");
export const FontContext = React.createContext("mono-space");
export const FontSizeContext = React.createContext("16px");
const Store = ({ children }) => {
const [lang, setLang] = useState("javascript");
const [font, setFont] = useState("mono-space");
const [fontSize, setFontSize] = useState("16px");
return (
<LangContext.Provider value={[lang, setLang]}>
<FontContext.Provider value={[font, setFont]}>
<FontSizeContext.Provider value={[fontSize, setFontSize]}>
{children}
</FontSizeContext.Provider>
</FontContext.Provider>
</LangContext.Provider>
);
};
I'm sure this is a bad practice but I'm not sure how to handle this. I want to be able to create a single context provider for all the contexts.
You can simply use a single provider and pass on the required values as an object:
export const StoreContext = React.createContext({});
const Store = ({ children }) => {
const [lang, setLang] = useState("javascript");
const [font, setFont] = useState("mono-space");
const [fontSize, setFontSize] = useState("16px");
return (
<StoreContext.Provider value={{lang, setLang, font, setFont, fontSize, setFontSize}}>
{children}
</StoreContext.Provider>
);
};
Also instead of using useState
you could modify the above to use useReducer
and make the API even simpler:
const initialState= {
lang: 'javascript',
font: 'mono-space',
fontSize: '16px',
}
const reducer = (state, action) => {
switch (action.type) {
case 'SET_LANG': return {...state, lang: action.payload}
case 'SET_FONT': return {...state, font: action.payload}
case 'SET_FONTSIZE': return {...state, fontSize: action.payload}
default: return state;
}
}
export const StoreContext = React.createContext({});
const Store = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<StoreContext.Provider value={[state, dispatch]}>
{children}
</StoreContext.Provider>
);
};
and in the child you can use it like:
const Child = () => {
const [state, dispatch] = useContext(StoreContext);
const handleChange = (size) => {
dispatch({type: 'SET_FONTSIZE', payload: size})
}
....
}