Production Level Context with Next.js (Typescript) ๐Ÿ”ฅ

Production Level Context with Next.js (Typescript) ๐Ÿ”ฅ

ยท

2 min read

Connect ๐Ÿ‘‹

Setup

First, let's create a file for defining the context (let's call it app-context.ts):

import React from "react";

export interface ContextState {
  name: string;
}

export interface ContextDispatch {
  setName: React.Dispatch<React.SetStateAction<string>>;
}

type ContextProps = ContextState & ContextDispatch;

const defaultState: ContextState = {
  name: "Hello",
};

const defaultDispatch: ContextDispatch = {
  setName: () => {},
};

const defaultContext: ContextProps = {
  ...defaultState,
  ...defaultDispatch,
};

const AppContext = React.createContext<ContextProps>(defaultContext);

export default AppContext;

Now, let's create a file for the provider component (let's call it app-context-provider.tsx):

"use client";
import React, { useState } from "react";
import AppContext, { ContextState, ContextDispatch } from "./appContext";

interface AppProviderProps {
  children: React.ReactNode;
}

const AppProvider: React.FC<AppProviderProps> = ({ children }) => {
  const [name, setName] = useState<string>("Hello");

  const contextState: ContextState = {
    name,
  };

  const contextDispatch: ContextDispatch = {
    setName,
  };

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

export default AppProvider;

Finally, let's create a custom hook for using the context (you can put this in a separate file or in the index.ts file):

import { useContext } from "react";
import AppContext from "./appContext";

export function useAppContext() {
  return useContext(AppContext);
}

Now you can use it in your application like this:

Wrap your app or a part of it with the AppProvider: layout.tsx

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={`${inter.className} bg`}>
        <AppProvider>{children}</AppProvider>
      </body>
    </html>
  );
}

Use the context in your components:

a-component.tsx

"use client";
import React from "react";
import { useAppContext } from "@/context";

const AComponent = () => {
  const { setName } = useAppContext();
  return (
    <div>
      <button
        className="default-button"
        onClick={() => {
          setName("Subham Maity");
        }}
      >
        Change The Name
      </button>
    </div>
  );
};

export default AComponent;

b-component.tsx

"use client";
import React from "react";
import { useAppContext } from "@/context";

const BComponent = () => {
  const { name } = useAppContext();
  return (
    <div>
      <p>{name}</p>
    </div>
  );
};

export default BComponent;

This structure provides better type safety, separates concerns, and is more scalable. It's easier to add new state variables and update functions as your app grows.

ย