组件的NextJS动态加载

hgb9j2n6  于 2023-03-18  发布在  其他
关注(0)|答案(1)|浏览(172)

我使用Sanity.io作为存储系统,希望根据内容类型动态加载组件。在构建器中,每个内容元素都被分配了一个“_type”值(如“Hero”或“Quote”),并且每个类型都有一个带有 prop 的对应组件。
由于内容管理器可能会以任意顺序使用未知数量的内容元素,因此我需要使用名为“getDynamicComponent”的函数为每个元素调用相应的组件。然后,该组件将显示其内部的内容。但是,我在使用Next/Image或PortableText组件时遇到了一个错误,我需要解决这个问题。

See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
error - TypeError: Cannot read properties of null (reading 'useContext')
    at stringify (<anonymous>)
error - TypeError: Cannot read properties of null (reading 'useMemo')
    at stringify (<anonymous>)
import { groq } from 'next-sanity'
import createClient from '../../lib/sanity.client'
import dynamic from 'next/dynamic'
import { RichtextComponents } from '@/components/RichText'
import { PortableText } from '@portabletext/react'
import { ComponentType } from 'react';

const pageQuery = groq`
    *[_type == "page_documents" && hidden == false] {
        ...,
        pageBuilder[]->
    } | order(_createdAt desc)
`

const getDynamicComponent = (type: string): ComponentType<any> => {
    let DynamicComponent;
    try {
        DynamicComponent = dynamic(() => import(`@/components/${type}`), {
            ssr: false,
            loading: () => <p>Loading...</p>,
        });
    } catch (err) {
        console.error(err);
        DynamicComponent = dynamic(() => import(`@/components/MissingComponent`), {
            ssr: false,
            loading: () => <p>Loading...</p>,
        });
    }
    return DynamicComponent;
};

const Home = async () => {
    const pages = await createClient.fetch(pageQuery)

    return (
        <>
            {
                pages.map((page: Page, index: number) => {
                    return (
                        <>
                            <div key={index}>
                                <>
                                    {
                                        page.pageBuilder.map((builder: any, index: number) => {
                                            // builder._type === 'Hero'
                                            const DynamicComponent = getDynamicComponent(builder._type);
                                            return (
                                                <div key={index}>
                                                    <PortableText
                                                        value={builder.body}
                                                        components={RichtextComponents}
                                                    /> {/* This is working */}

                                                    {DynamicComponent && <DynamicComponent {...builder} />}
                                                </div>
                                            );
                                        })
                                    }
                                </>
                            </div>
                        </>
                    )
                })
            }
        </>
    )
}

export default Home

Hero组件:指定的属性不是“null”或“undefined”。这不应该是问题所在。我可以输出单个属性,但当我使用Next/Image之类的属性时,它不起作用。
一个二个一个一个
这是正确的做法,还是有更好的方法来达到预期的结果?

dfuffjeb

dfuffjeb1#

感谢www.example.com上的rafaelalmeidatk#7126discord.gg/nextjs
我完全同意这个解决方案

import { groq } from 'next-sanity'
import createClient from '../../lib/sanity.client'
import dynamic from 'next/dynamic'
import { ComponentType } from 'react';

interface SanityComponents<T> {
    [key: string]: ComponentType<T>;
}

const sanityComponents: SanityComponents<any> = {
    Hero: dynamic(() => import('@/components/Hero')),
    // ...
};

const pageQuery = groq`
    *[_type == "page_documents" && hidden == false] {
        ...,
        pageBuilder[]->
    } | order(_createdAt desc)
`

const Home = async () => {
    const pages = await createClient.fetch(pageQuery)

    return (
        <>
            {
                pages.map((page: Page, index: number) => {
                    return (
                        <div key={index}>
                            {
                                page.pageBuilder.map((builder: any, index: number) => {
                                    const SanityComponent = sanityComponents[builder._type]
                                    return <SanityComponent {...builder} key={builder._id} />
                                })
                            }
                        </div>
                    )
                })
            }
        </>
    )
}

export default Home

相关问题