Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persisting state and context on locale change in nextjs 13 and next-intl #496

Closed
woutervdlaan opened this issue Sep 1, 2023 · 7 comments
Labels
bug Something isn't working unconfirmed Needs triage.

Comments

@woutervdlaan
Copy link

Description

I am building a nextjs (v13) app routed website that uses next-intl for internationalization.

I am trying to figure out a way to have some context and state persist on locale change.
When locale is changed on the page, next-intl useRouter API is used to direct to the correct locale route: app/[locale]/...rest. This seems to reset everything, including context that is not a child of NextIntlClientProvider.

I am using Prefix-based routing ('example.com/en/...rest', or 'example.com/nl/...rest') which is default.

------ My folder structure looks like this (following next-intl docs): ------

  • messages (en.json, nl.json)
  • middleware.ts
  • contexts (testContext.tsx)
  • app ([locale] (layout.tsx, page.tsx))

├── messages
│ ├── en.json
│ └── nl.json
├── middleware.ts
├── contexts
│ ├── testContext.tsx
└── app
└── [locale]
├── layout.tsx
└── page.tsx

------ '/middleware.ts' looks like this: ------

import createMiddleware from "next-intl/middleware";

export default createMiddleware({
locales: ["en", "nl"],
defaultLocale: "en",
});

export const config = {
matcher: ["/((?!api|_next|.\..).*)"],
};
------ '/contexts/testContext.tsx' looks like this: ------

"use client";

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

type TestContext = {
showDiv: boolean;
setShowDiv: Dispatch<SetStateAction>;
};

export const TestContext = createContext<TestContext | null>(null);

const TestContextProvider = ({ children }: { children: ReactNode }) => {
const [showDiv, setShowDiv] = useState(false);

return (
<TestContext.Provider value={{ showDiv, setShowDiv }}>
{children}
</TestContext.Provider>
);
};

export default TestContextProvider;
------ And the '/app/[locale]/layout.tsx' is as follows: ------

import { NextIntlClientProvider } from "next-intl";
import { notFound } from "next/navigation";
import TestContextProvider from "@/contexts/testContext";

export function generateStaticParams() {
return [{ locale: "en" }, { locale: "nl" }];
}

export default async function RootLayout({
children,
params: { locale },
}: {
children: React.ReactNode;
params: { locale: string };
}) {
let messages;
try {
messages = (await import(../../messages/${locale}.json)).default;
} catch (error) {
notFound();
}

return (



{children}



);
}
This is a testProject to specify this issue. In another- real- project this functionality would allow for (i.e.) my stateful dropdown menu (which includes a locale switch button) to remain in a state op being opened on locale change (which is being stored in a context outside of NextIntlClientProvider).

I have tried using the various UseRouter, UsePathname, Link and other hooks that are offered by next-intl as an extension of the native nextjs UseRouter, UsePathname and other hooks and functions, expecting this to take into consideration the specificities of locale switching (which ought to switch locale with the least amount of disruption.)

I have tried nesting the NextIntlClientProvider more deeply in the RootLayout, thereby only affecting more nested components. But this still triggered a total reset of external state and context.

I have tried relocating the RootLayout.tsx before the [locale] folder, thereby preventing the locale and route change to affect RootLayout (which holds my state and context). However, this would mean my Rootlayout can't use the internationalization as it is no longer embedded into the locale detection flow. Furthermore, if I would want to use internationalized metadata that uses translations, I would need to locate this within the [locale] detection and flow.

Mandatory reproduction URL (CodeSandbox or GitHub repository)

https://github.com/woutervdlaan/intl-test-app

Reproduction description

Steps to reproduce:

  1. Open repo

  2. Clone repo

  3. run 'npm run dev' and go to localhost:3000

  4. when clicking on button 'LANGUAGE CHANGE' the locale switches and language is changed (Hello world => Hallo wereld) and this should ALSO setState of showDiv, which is stored in testContext outside of NextIntlClientProvider

  5. page refreshes and context is reset instead of persisted.

Expected behaviour

TestContext is stored outside of NextIntlClientProvider, therefore I expect only relevant components to remount and NOT TestContext. How can it be that is still seems to reload page entirely?

@woutervdlaan woutervdlaan added bug Something isn't working unconfirmed Needs triage. labels Sep 1, 2023
@amannn
Copy link
Owner

amannn commented Sep 2, 2023

Is this vercel/next.js#44793? This might be outside of the control of next-intl.

@Laktus
Copy link

Laktus commented Oct 3, 2023

Hello,
How can we solve this issue? I'm using "Zustand" for state management and my state information gets lost when i try to change the language.
Can i use Client Components somehow to solve this?

@amannn
Copy link
Owner

amannn commented Oct 4, 2023

Hmm, where are you creating your zustand store? I haven't used this so far, but I could imagine if the code where the store is created remains loaded, then the state should be retained.

If you're using React Context, I think if you add a provider in app/layout.tsx, then the state should persist over a locale change.

@amannn
Copy link
Owner

amannn commented Nov 14, 2023

There hasn't been any updates in this thread, I'm closing this due to inactivity. Please open a new issue in case you see a bug that is caused by next-intl.

@amannn amannn closed this as completed Nov 14, 2023
@HHX123
Copy link

HHX123 commented Dec 14, 2023

Hello, How can we solve this issue? I'm using "Zustand" for state management and my state information gets lost when i try to change the language. Can i use Client Components somehow to solve this?

same problem,anybody solved it?

@Laktus
Copy link

Laktus commented Dec 14, 2023

For me i had the problem when clicking on the language toogle. How i fixed it is by defining the language toogle as 'use client' and add

<NextIntlClientProvider locale={locale} messages={messages}>
</NextIntlClientProvider> 

to my respective layout that contained my toggle.

@pavliklaw7-ni-solutions
Copy link

In my case I have solved this issue by using window object to store data like this:
if (typeof window !== 'undefined') { // @ts-ignore window.someData = someData }

you also have to add someData.d.ts in src to ensure ts error
declare global { interface Window { someData: any; } }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working unconfirmed Needs triage.
Projects
None yet
Development

No branches or pull requests

5 participants