Next.js Discord

Discord Forum

Setting useContext value inside a client component onclick?

Unanswered
Greenish Elaenia posted this in #help-forum
Open in Discord
Greenish ElaeniaOP
I have a sign in button onclick in a client component
When clicking the button, an api route handler is called. The route handler returns a NextResponse with a body containing user data.
I want to set value of the AuthContext to this user data in the client component before the useRouter pushes the next page.
OR maybe get the response body in the server component that is the next page and set the context there?
What's the best way to set context that is event driven?

10 Replies

Sun bear
Create AuthContext component:

"use client";

import { createContext, Dispatch, SetStateAction } from "react";
import { useState } from "react";

type AuthContextType = {
  user: string | null;
  setUser: Dispatch<SetStateAction<string | null>>;
};

export const AuthContext = createContext<AuthContextType | null>(null);

export default function AuthContextProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  const [user, setUser] = useState<string | null>(null);

  return (
    <AuthContext.Provider value={{ user, setUser }}>
      {children}
    </AuthContext.Provider>
  );
}
Create useAuthContext helper hook:

import { AuthContext } from "@/components/AuthContext";
import { use } from "react";

export default function useAuthContext() {
  const context = use(AuthContext);

  if (!context) {
    throw new Error(
      "useAuthContext must be used within an AuthContextProvider"
    );
  }

  return context;
}
Query the api for user, await the response and set the user using our helper hook:

"use client";

import useAuthContext from "@/hooks/useAuthContext";
import { useRouter } from "next/navigation";
import { FormEvent } from "react";

export default function Home() {
  const router = useRouter();
  const { setUser } = useAuthContext();

  async function onSubmit(e: FormEvent) {
    e.preventDefault();

    const res = await fetch("/api/user");
    const data = await res.json();

    if (data.user) setUser(data.user);

    router.push("/success");
  }

  return (
    <main>
      <form onSubmit={(e) => onSubmit(e)}>
        <button type="submit">Submit</button>
      </form>
    </main>
  );
}
Access the user using our helper hook somewhere else in the application:

"use client";

import useAuthContext from "@/hooks/useAuthContext";

export default function Success() {
  const { user } = useAuthContext();

  return <div>{user}</div>;
}
Greenish ElaeniaOP
@Sun bear really appreciate the assist, was stuck at the setUser: Dispatch syntax, where context wraps both the value and a dispatch. Great idea
Sun bear
this is usually the approach without using state management libraries, however if you are looking to minimise this code you should look at [jotai](https://jotai.org/). it's not like redux where you write more code then you would otherwise.

it takes you from this jumble above to just wrapping the application with jotai provider and this:

// src/atoms/user.ts
import {atom} from "jotai"

const userAtom = atom<UserType | null>(null)

export default function useUser() {
  const [user, setUser] = useAtom(userAtom)

  return {user, setUser}
}


Then you can just import this hook somewhere in the application and use it.

It has two advantages to using Context, first it uses less code which makes it more readable and intuitive and second it does not rerender all components in the dom tree below it but just the ones that depend on it, making it more performant than standalone react.
Greenish ElaeniaOP
I looked into jotai and really like how it doesnt have dependencies - the project im refactoring was primarily suffering from dependency hell where our libraries depended on vulnerable old libraries AND a specific version of react and typescript, meaning I can't address vulnerabilities in react and typescript either
all breaking changes
still, I couldnt convince the top brass to use jotai so raw Context api it is
appreciate the rec tho will play around with it in my own projects