How to update state from child component in Next.js?
Answered
African Slender-snouted Crocodil… posted this in #help-forum
Original message was deleted.
Answered by joulev
there are three solutions to this.
1. restructure the layout so that the title is rendered in the page. the layout is supposed to be shared for all pages so should not change when you navigate between pages under it
2. use parallel routing:
then you return the title from
3. use a client component with an existing list of title, like
then import that
1. restructure the layout so that the title is rendered in the page. the layout is supposed to be shared for all pages so should not change when you navigate between pages under it
2. use parallel routing:
layout.tsx
my-page/page.tsx
@title/my-page/page.tsxthen you return the title from
@title/my-page/page.tsx, then you can get that title in the title prop of the layoutfunction Layout({ children, title }) {
return (
<div>
<h1>{title}</h1>
<main>{children}</main>
</div>
);
}3. use a client component with an existing list of title, like
export const meta = [
{
pathname: "/page-1",
title: "Page 1",
// ... other metadata you also want to render in the layout
},
// ... other pages
];then import that
meta object to a client component title component where you use usePathname/useParams to detect the current page and retrieve the title from the object given the pathname you found from those hooks19 Replies
I dont get what you are trying to do and its late so my brain not braining, but since its a component, why are you returning null instead of a react fragment or something.
#Unknown Channel</>
#Unknown Channel</>
returning null is a valid way to specify that a component doesnt render anything to the DOM
if the parent
<Page /> was a client component, you can encapsulate the usePageTitle and useEffect logic inside a custom React hook and use it inside <Page />. but since <Page /> is a server component here that's not possible since you need a client component somewhere to handle this client-side stuffif you do have another client component in the page then you can simply do
and use this
function useWhateverNameYouWant() {
const { setPageTitle } = usePageTitle();
useEffect(() => {
setPageTitle(pageTitle);
}, [pageTitle, setPageTitle]);
}and use this
useWhateverNameYouWant inside a client component in the pageid say a component rendering nothing is not a bad practice, i use it all the time as well for cases like this
personally i think page titles should never be managed this way and an
useEffect should be avoided whenever possiblebut in this case, if you want to go ahead with the hook approach then returning null is imo the best solution
use the metadata API (
export const metadata and similar) wherever possibleif you have to handle the title from a client component, then https://nextjs-faq.com/metadata-client-components
"use client";
import { useState } from "react";
export default function Page() {
const [title, setTitle] = useState("Hello World");
return (
<div>
{/* Yes, we simply put the <title> tag anywhere in the document. */}
<title>{title}</title>
<input value={title} onChange={e => setTitle(e.target.value)} />
</div>
);
}export async function generateMetadata() {
const data = await getData();
return { title: data.title };
}yes honestly the app router requires a big shift in the mindset
@joulev tsx
"use client";
import { useState } from "react";
export default function Page() {
const [title, setTitle] = useState("Hello World");
return (
<div>
{/* Yes, we simply put the <title> tag anywhere in the document. */}
<title>{title}</title>
<input value={title} onChange={e => setTitle(e.target.value)} />
</div>
);
}
but if you used to use
next/head in the pages router, you can simply choose the client component method and it will just work, just remove the wrapping <Head> like thisoh i see, so you are not talking about the metadata here but merely the text content of an element
hmm so am i right in saying this? you are rendering the title in the layout component, but you want to change the content of that element when changing page so you use this useEffect hook to update the title?
there are three solutions to this.
1. restructure the layout so that the title is rendered in the page. the layout is supposed to be shared for all pages so should not change when you navigate between pages under it
2. use parallel routing:
then you return the title from
3. use a client component with an existing list of title, like
then import that
1. restructure the layout so that the title is rendered in the page. the layout is supposed to be shared for all pages so should not change when you navigate between pages under it
2. use parallel routing:
layout.tsx
my-page/page.tsx
@title/my-page/page.tsxthen you return the title from
@title/my-page/page.tsx, then you can get that title in the title prop of the layoutfunction Layout({ children, title }) {
return (
<div>
<h1>{title}</h1>
<main>{children}</main>
</div>
);
}3. use a client component with an existing list of title, like
export const meta = [
{
pathname: "/page-1",
title: "Page 1",
// ... other metadata you also want to render in the layout
},
// ... other pages
];then import that
meta object to a client component title component where you use usePathname/useParams to detect the current page and retrieve the title from the object given the pathname you found from those hooksAnswer
Original message was deleted
parallel routing is actually pretty simple, you just create additional pages that will go to props like
approach #3 is what im doing here https://github.com/joulev/website/blob/blog/src/app/(public)/blogs/meta.ts
children. you can see e.g. here https://github.com/joulev/website/tree/5bde46c637a1a059d812858e420a3d01d9cd3db5/src/app/(public)/blogs. i scrapped this approach for my blog though because i find it to not be maintainable, i'd have to create like 10s of these props to achieve what i wantapproach #3 is what im doing here https://github.com/joulev/website/blob/blog/src/app/(public)/blogs/meta.ts
i think as far as maintainability is concerned, any solutions that trigger state updates inside useEffect should be out of the question
all three options have merits and drawbacks, but i think all of them are far more bearable than the horror caused by side effects that trigger state updates that trigger yet more side effects that trigger yet more state updates...