next.jsnextjs-dynamic-routingapp-router

How to dynamically set Metadata in NextJs 14 App router, from root layout file?


I am using Redux Toolkit to handle all the data. Every page of my application has it's own singular state. State along with Metadata is fetched/populated at page load.

Now i want to set Metadata based on the data present in state.

I've already tried generateMetadata provided by nextjs. I have hooks defined in my project which gets the data from state based on current route path. Is there something that i'm missing?


Solution

  • // app/[MovieID]/page.js
    import { fetchSingleMovie } from "@/lib/moviesFetch";
    export async function generateMetadata({ params }) {
        const movie = await fetchSingleMovie(params.MovieID);
        if (!movie) {
            return {
                title: 'tv.onvo Movies',
                description: 'The requested movie was not found.',
            };
        }
    
        return {
    
            title: `${movie[0]['l']} movie`,
            description: `${movie[0]['l']} movie`,
            openGraph: {
                title: `${movie[0]['l']}`,
                description: `watch ${movie[0]['l']} on tv.onvo`,
                images: [
                    { url: movie[0]['i']['imageUrl'], width: 800, height: 600 },
                ],
            },
            twitter: {
                card: `tv.onvo movie`,
                title: `${movie[0]['l']} movie`,
                description: `${movie[0]['l']} movie`,
                siteId: `${params.MovieID}`,
                creator: '@onvo_me',
                creatorId: '1467726470533754880',
                images: {
                    url: 'https://onvo.me',
                    alt: 'onvo Logo',
                },
                app: {
                    name: 'twitter_app',
                    id: {
                        iphone: 'twitter_app://iphone',
                        ipad: 'twitter_app://ipad',
                        googleplay: 'twitter_app://googleplay',
                    },
                    url: {
                        iphone: 'https://iphone_url',
                        ipad: 'https://ipad_url',
                    },
                },
            },
            alternates: {
                canonical: 'https://onvo.me',
                languages: {
                    'en-US': 'https://onvo.me',
                    'de-DE': 'https://onvo.me',
                },
                media: {
                    'only screen and (max-width: 600px)': 'https://onvo.me/',
                },
                types: {
                    'application/rss+xml': 'https://onvo.me/',
                },
            },
            appLinks: {
                ios: {
                    url: 'https://onvo.me/',
                    app_store_id: 'app_store_id',
                },
                android: {
                    package: 'com.example.android/package',
                    app_name: 'app_name_android',
                },
                web: {
                    url: 'https://onvo.me/',
                    should_fallback: true,
                },
            },
            bookmarks: ['https://onvo.me/13'],
            category: 'entertainment',
        };
    };
    
    export default async function Page({ params }) {
        const movie = await fetchSingleMovie(params.MovieID);
    
        if (!movie) {
            return (
                <NoMovies />
            );
        }
    
        return (
            <div className="flex min-h-screen flex-col items-center justify-between md:px-16 md:mt-4 p-2">
                <h1>{movie[0].l}</h1>
            </div>
        );
    }
    

    that's an example of dynamic metadata generated on the server for each movie id slug right after app router '/ home router'