0

Starting with ReactJS and NextJS

I have the following Layout component and using context to set values from the children component

export interface AuthContextModel {
    title: string;
    description: string;
    showSignup: boolean;
}

export const AuthContext = createContext(null);

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

    const [authContext, setAuthContext] = useState<AuthContextModel>();

    return (
        <>
            <Head>
                <title>Authentication</title>
                <HeadComponent/>
            </Head>

            <AuthContext.Provider value={setAuthContext}>

                <h4>{authContext?.title}</h4>
                <p className="text-muted mb-4">Sign in to continue to Chatvia.</p>
                {children}

            </AuthContext.Provider>
        </>
    )
}

And the Login page extends the Layout

export default function Login(props) {
    const setAuthContext = useContext(AuthContext);

    useEffect(() => {
        setAuthContext({
            title: 'Sign In'
        })
    }, [])

    return (
        <AuthLayout>
            <form onSubmit={handleSubmit}>

                ...

            </form>
        </AuthLayout>
    )
}

But the setAuthContext in the Login function is giving the following error

TypeError: setAuthContext is not a function

How can I update the context variable from the children component?

Anuj TBE
  • 9,198
  • 27
  • 136
  • 285

1 Answers1

0

When you mount the Login, that component is not a child of AuthLayout. As a result, Login will not gain access to AuthContext.

If you wanted Login to have access to AuthContext, it would need to be mounted something like this:

<AuthLayout>
  <Login />
</AuthLayout>

Right now, you're mounting it like this:

<AuthLayout>
  {/* Something else */}
</AuthLayout>
<Login />

The consumer (Login) is not a child of the provider (AuthLayout), so the consumer currently can't get anything from that context unless it is a child of the provider.

https://reactjs.org/docs/context.html

Shea Hunter Belsky
  • 2,815
  • 3
  • 22
  • 31
  • `AuthLayout` is a wrapper function and the `Login` is rendered inside the AuthLayout using `{children}`. Initially it is not sure the which page to render, the `{children}` will dynamically load the page content. How can I put `` in the AuthLayout because it could be SignUp or ForgotPassword, etc wrapped in AuthLayout? – Anuj TBE Feb 03 '22 at 03:11
  • `Login` is not child of `AuthLayout` - The rendered contents of `Login` _are_ children of `AuthLayout`, but the `Login` component itself is not. `Login` must be a direct child of `AuthLayout` to access any context that it exposed. See the pseudo code I wrote in my original answer for what I mean. – Shea Hunter Belsky Feb 03 '22 at 19:18
  • So as I want to change the title and description content on the Layout page to the page loaded, similar to `Login` there will be `Signup` and `ForgotPassword` components as well. So you mean that instead of using `{children}` in the `AuthLayout`, I should use ``? Will, not it load all the pages altogether? – Anuj TBE Feb 04 '22 at 12:30
  • The last bit of code is what you need. In order for `Login` to access the context provided by `AuthLayout`, it must be mounted as a child of `AuthLayout`. In your original answer, `Login` is mounting `AuthLayout`, but that does not grant `Login` access to its context. `Login` must be a child of `AuthLayout` in order to access its context. – Shea Hunter Belsky Feb 04 '22 at 18:53