How to initialize the state of a Context before providing it in React/Next.js?

Viewed 33

I'm developing a website using Next.jsand I'm using a Layout component. What I'm trying to do is to wrap the children of my Layout in a Context Provider, but I need to initialize the state of the Context inside the Layout, but outside the provider.

This is the code for my Context:

// at contexts/ParametrosContext.js

import { createContext, useState } from "react";

export const ParametrosContext = createContext({});

export const ParametrosProvider = ({ children }) => {

    const [parametros, setParametros] = useState({});

    function loadParametrosContext(parametrosObj) {
        setParametros(parametrosObj);
    }

    return (
        <ParametrosContext.Provider value={{ parametros, loadParametrosContext }}>
            { children }
        </ParametrosContext.Provider>
    )
}

Then, my Layout:

// at components/layouts/SiteLayout.js

import { ParametrosContext, ParametrosProvider } from "../../contexts/ParametrosContext";

export default function SiteLayout({ children }) {

    const { loadParametrosContext } = useContext(ParametrosContext);

    if (children.props.ConteudoSite.temParametros)
            loadParametrosContext(children.props.ConteudoSite.Parametros);

    return ( 
        <ParametrosProvider>
            <Header/>
            {
                children
            }
            <Footer/>
        </ParametrosProvider>
    )
}

As seen in the SiteLayout component's code, I'm trying to call a function of my Context before wrapping the children in the Provider, because is here in the Layout that I have the data to initialize de Context's state, but this is giving me TypeError: loadParametrosContext is not a function.

Is there a correct way to do this what I'm trying?

1 Answers

useContext get context value from nearest parent provider, since SiteLayout is the one rendering the provider, there is no context at that point.

Either the ParametrosProvider is renderer as parent of SiteLayout or you can use a intermediary component inside SiteLayout that use the context


const LoadParametros = ({ parametros, children }) => {
  const { loadParametrosContext } = useContext(ParametrosContext);

  useEffect(() => {
    if (loadParametrosContext && parametros) {
     loadParametrosContext(parametros);
    }
  }, [parametros]);

  return children;
}
export default function SiteLayout({ children }) {
  return ( 
    <ParametrosProvider>
       <LoadParametros parametros={children.props.conteudoSite.Parametros}>
         <Header/>
         {children}
         <Footer/>
       </LoadParametros>
    </ParametrosProvider>
  );
}
Related