How to use Context Api in Next.js

Viewed 2136

First I would like to say to I've never worked with either next.js or the context api so please bear with me.

I'm currently working on a web application in Next.js where I have multiple pages that each contain a form. I would like to have a global state of some sort in order to be able to set and update the data from each form. All form data together

For example: page 1 = name, page 2 = description, ...

From what I've read online, I thought that using the context api would be sufficient, but I've hit a wall. When I fill in the name on the first form it doesn't get saved in the global state because it doesn't show up on the second page.

I don't understand where I went wrong so any help i more than welcome!

p.s. if i didn't explain some part right or forgot to add some code snippet please let me know.

businessContext.tsx

import { createContext, useState } from "react";

//accessible data
export interface BusinessContextData {
  businessName: string;
  handleBusinessName: (name: string) => void;
}

//default values
export const businessContextDefaultValue: BusinessContextData = {
  businessName: "",
};

//provider
export const BusinessContext = createContext<BusinessContextData>(
  businessContextDefaultValue
);

//hooks that components can use to change the values
export function useBusinessContextValue(): BusinessContextData {
  const [businessName, setBName] = useState<string>("");

  const handleBusinessName = (name: string) => {
    setBName(name);
  };

  return {
    businessName,
    handleBusinessName,
  };
}

_app.tsx

import type { AppProps } from "next/app";
import {
  useBusinessContextValue,
  BusinessContext,
} from "../context/businessContext";
import "../styles/global.css";

function MyApp({ Component, pageProps }: AppProps) {
  const businessContextValue = useBusinessContextValue();

  return (
    <BusinessContext.Provider value={businessContextValue}>
      <Component {...pageProps} />
    </BusinessContext.Provider>
  );
}

export default MyApp;

businessName.tsx - name form page (should save the given name in global state)

import { ChangeEvent, FormEvent, useContext, useState } from "react";
import { BusinessContext } from "../context/businessContext";

const IndexPage = () => {
  const { handleBusinessName } = useContext(BusinessContext);
  const router = useRouter();
  const [businessNameState, setBusinessnameState] = useState<string>("");

  const onSubmit = (e: FormEvent) => {
    handleBusinessName(businessNameState);
    router.push("/businessVision");
  };

  return (
        ...
        <form onSubmit={(e: FormEvent) => onSubmit(e)}>
          <div className="formInputRow">
            <input
              className="formInput"
              type="text"
              placeholder="Business name"
              required
              value={businessNameState}
              onChange={(val: ChangeEvent<HTMLInputElement>) =>
                setBusinessnameState(val.target.value)
              }
            />
          </div>
          <button type="submit">
            Next
          </button>
        </form>
        ...
  );
};

export default IndexPage;

businessVision.tsx - should display business name from global state

import { ChangeEvent, FormEvent, useContext, useEffect, useState } from "react";
import { BusinessContext } from "../context/businessContext";

const BusinessVisionpage = () => {
  const { businessName } = useContext(BusinessContext);
  const router = useRouter();
  const [businessVisionState, setBusinessVisionState] = useState<string>("");

  return (
        ...
        <h1>
          <span>{businessName}</span>
        </h1>
        ...
  );
};

1 Answers

Your context is setup correctly, but you'll need to prevent the <form>'s submit default behaviour so that the navigation to the next page can happen properly.

const onSubmit = (e: FormEvent) => {
    e.preventDefault(); // Prevents submit default behaviour
    handleBusinessName(businessNameState);
    router.push("/businessVision");
};
Related