5

Is it possible in Next JS 13 to fetch data on the server but then propagate it to Context API?

In my case, I want to fetch user information via token on the server, but then pass it to Context API since I may use user data somewhere else in the app. The problem is that Context API is a client-side technology, so wherever I want to use it I end up declaring client components with 'use client'. Is it possible to get the best of two worlds?

2
  • Did you end up finding a solution? I'm just starting to learn NextJS and ran into this question. Commented Aug 10, 2023 at 11:41
  • There is no way to pass data from client to server with Context API. But you can try zustand as was mentioned by Mayank Kumar Chaudhari. It's a super easy to use state management system, you should definitely give it a try. Commented Aug 28, 2023 at 7:41

2 Answers 2

0

It is not possile to use context with ServerSide component. You can use zustand for creating global state that does not require elements to be wrapped inside a provider.

Sign up to request clarification or add additional context in comments.

Comments

0

This scenario gives you a typical example of how you can manage user details in the context API and also persist the value of the context API using Next.js

Create a folder called "context" and create an index.tsx inside it

here is the content of the file


import React, { createContext, useContext, useState, useEffect } from "react";

// Define the context type
type ContextType = {
  user: any;
  token: string | null;
  isAuthenticated: boolean;
  updateAppState: (newState: Partial<ContextType>) => void;
};

// Create the context with a default value
const AppContext = createContext<ContextType>({
  user: null,
  token: null,
  isAuthenticated: false,
  updateAppState: () => {},
});

export const AppWrapper = ({ children }: { children: React.ReactNode }) => {
  const [appState, setAppState] = useState<ContextType>(() => {
    // Load the state from localStorage on initial render
    if (typeof window !== "undefined") {
      const storedState = localStorage.getItem("appState");
      return storedState
        ? JSON.parse(storedState)
        : {
            user: null,
            token: null,
            isAuthenticated: false,
            updateAppState: () => {},
          };
    }
    // Default state if localStorage is empty or unavailable
    return {
      user: null,
      token: null,
      isAuthenticated: false,
      updateAppState: () => {},
    };
  });

  // Save state to localStorage whenever it changes
  useEffect(() => {
    localStorage.setItem("appState", JSON.stringify(appState));
  }, [appState]);

  // Custom function to update the app state
  const updateAppState = (newState: Partial<ContextType>) => {
    setAppState((prevState) => ({
      ...prevState,
      ...newState,
    }));
  };

  return (
    <AppContext.Provider value={{ ...appState, updateAppState }}>
      {children}
    </AppContext.Provider>
  );
};

// Custom hook to use the context
export const useAppContext = () => {
  return useContext(AppContext);
};

Here is a use case of how it can be utilised. This is more like you protecting a particular route. You can tailor this to you need as the case may be for you.


import React, { useEffect, useRef } from "react";
import { useAppContext } from "@/app/utils/context";
import { useRouter } from "next/navigation";
import { openNotificationWithIcon } from "@/app/utils/helper";

const RootLayout = ({ children }: { children: React.ReactNode }) => {
  const { user, token, isAuthenticated } = useAppContext();
  const router = useRouter();
  const hasNotified = useRef(false); // To track whether the notification has been shown

  useEffect(() => {
    if (!token || !isAuthenticated || !user || user?.userType !== "admin") {
      if (!hasNotified.current) { // Check if the notification has already been shown
        hasNotified.current = true;
        openNotificationWithIcon("warning", "Login to continue...");
      }
      router.push("/");
    }
  }, [user, token, isAuthenticated, router]);

  return <div>{children}</div>;
};

export default RootLayout;```

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.