gpt4 book ai didi

javascript - Next.js 在组件内获取数据的最佳实践

转载 作者:行者123 更新时间:2023-12-03 13:32:36 25 4
gpt4 key购买 nike

我有一个全局显示的菜单组件。将数据导入该组件的最佳做法是什么?
我正在尝试利用 Next.js 提供的静态生成,但所有 data fetching Next.js 团队的指导与页面有关。 getStaticPropsgetStaticPaths似乎与页面生成有关,而不是组件的数据。是他们的SWR打包正确答案,还是 Apollo Client?
通常在基于钩子(Hook)的 React 中,我只需将数据调用放入 useEffect .我不确定如何推断出所有内容都是在构建时使用 Next 渲染的。

最佳答案

这是一个非常棘手的问题,我认为我们需要在解决方案成为焦点之前布置一些背景。我专注于 React.js 世界,但我想其中很多都适用于 Vue/Nuxt。
背景/静态生成的好处:
Gatsby 和 Next 专注于生成静态页面,这极大地提高了 React.js 网站的性能和 SEO。除了这个简单的见解之外,这两个平台还有很多技术开销,但让我们从数字机器为浏览器输出精美的 HTML 页面的想法开始。
页面数据获取
对于 Next.js(截至 v9.5),它们的数据获取机制 getStaticProps 为您完成大部分繁重的工作,但它被沙盒化到 /pages/目录。这个想法是它为您获取数据并在构建期间告诉 Node 中的 Next.js 页面生成器(而不是在 useEffect Hook 或 componentDidMount 中进行组件端)。 Gatsby 的 gatsby-node.js 也是如此。文件,它与 Node 服务器一起协调页面构建的数据获取。
需要数据的全局组件呢?
您可以同时使用 Gatsby 和 Next 来制作任何类型的网站,但一个巨大的用例是 CMS 驱动的网站,因为其中大部分内容是静态的。这些工具非常适合该用例。
在典型的 CMS 站点中,您将拥有全局元素 - 页眉、页脚、搜索、菜单等。这是静态生成面临巨大挑战的地方:如何在构建时将数据获取到动态全局组件中?这个问题的答案是……你不知道。如果你想一分钟,这是有道理的。如果您有一个 10K 页的网站,如果有人将新的导航项添加到菜单中,您是否希望触发站点范围的重建?
全局组件的数据获取
那么我们如何解决这个问题呢?我的最佳答案是apollo-client并做 fetch 客户端。这对我们有很多帮助:

  • 对于小型查询,性能影响可以忽略不计。
  • 如果我们需要为 CMS 层的更改重建页面,这会通过 Next/Gatsby 的检测机制滑动,因此我们可以进行全局更改而不会触发巨大的站点范围的重建。

  • 那么这实际上是什么样子的呢?在组件级别,它看起来就像一个普通的 Apollo 增强组件。我一般用 styled-components但我试图把它去掉,这样你就可以更好地看到发生了什么。
    import React from 'react'
    import { useQuery, gql } from '@apollo/client'
    import close from '../public/close.svg'

    /**
    * <NavMenu>
    *
    * Just a typical menu you might see on a CMS-driven site. It takes in a couple of props to move state around.
    *
    * @param { boolean } menuState - lifted state true/false toggle for menu opening/closing
    * @param { function } handleMenu - lifted state changer for menuState, handles click event
    */

    const NAV_MENU_DATA = gql`
    query NavMenu($uid: String!, $lang: String!) {
    nav_menu(uid: $uid, lang: $lang) {
    main_menu_items {
    item {
    ... on Landing_page {
    title
    _linkType
    _meta {
    uid
    id
    }
    }
    }
    }
    }
    }
    `

    const NavMenu = ({ menuState, handleMenu }) => {
    // Query for nav menu from Apollo, this is where you pass in your GraphQL variables
    const { loading, error, data } = useQuery(NAV_MENU_DATA, {
    variables: {
    "uid": "nav-menu",
    "lang": "en-us"
    }
    })

    if (loading) return `<p>Loading...</p>`;
    if (error) return `Error! ${error}`;

    // Destructuring the data object
    const { nav_menu: { main_menu_items } } = data

    // `menuState` checks just make sure out menu was turned on
    if (data) return(
    <>
    <section menuState={ menuState }>
    <div>
    { menuState === true && (
    <div>Explore</div>
    )}
    <div onClick={ handleMenu }>
    { menuState === true && (
    <svg src={ close } />
    )}
    </div>
    </div>
    { menuState === true && (
    <ul>
    { data.map( (item) => {
    return (
    <li link={ item }>
    { item.title }
    </li>
    )
    })}
    </ul>
    )}
    </section>
    </>
    )
    }

    export default NavMenu
    设置下一个使用 Apollo
    Next.js 团队实际上已经很好地记录了这一点,这让我觉得我并没有完全破解这个工具的工作方式。您可以找到 great examples of using Apollo在他们的 repo 中。
    让 Apollo 进入 Next 应用程序的步骤:
  • 定制useApollo用于建立与您的数据源的连接的钩子(Hook)(我将我的放在 /lib/apollo/apolloClient.js 中 Next 的层次结构中,但我确信它可以放在其他地方)。
  • import { useMemo } from 'react'
    import { ApolloClient, InMemoryCache, SchemaLink, HttpLink } from '@apollo/client'

    let apolloClient

    // This is mostly from next.js official repo on how best to integrate Next and Apollo
    function createIsomorphLink() {
    // only if you need to do auth
    if (typeof window === 'undefined') {
    // return new SchemaLink({ schema })
    return null
    }
    // This sets up the connection to your endpoint, will vary widely.
    else {
    return new HttpLink({
    uri: `https://yourendpoint.io/graphql`
    })
    }
    }

    // Function that leverages ApolloClient setup, you could just use this and skip the above function if you aren't doing any authenticated routes
    function createApolloClient() {
    return new ApolloClient({
    ssrMode: typeof window === 'undefined',
    link: createIsomorphLink(),
    cache: new InMemoryCache(),
    })
    }


    export function initializeApollo(initialState = null) {
    const _apolloClient = apolloClient ?? createApolloClient()

    // If your page has Next.js data fetching methods that use Apollo Client, the initial state
    // gets hydrated here
    if (initialState) {
    // Get existing cache, loaded during client side data fetching
    const existingCache = _apolloClient.extract()
    // Restore the cache using the data passed from getStaticProps/getServerSideProps
    // combined with the existing cached data
    _apolloClient.cache.restore({ ...existingCache, ...initialState })
    }
    // For SSG and SSR always create a new Apollo Client
    if (typeof window === 'undefined') return _apolloClient
    // Create the Apollo Client once in the client
    if (!apolloClient) apolloClient = _apolloClient

    return _apolloClient
    }

    // This is goal, now we have a custom hook we can use to set up Apollo across our app. Make sure to export this!
    export function useApollo(initialState) {
    const store = useMemo(() => initializeApollo(initialState), [initialState])
    return store
    }
  • 修改_app.js/pages/ Next 的目录。这基本上是 Next 中每个页面的包装器。我们将向其中添加 Apollo 提供程序,现在我们可以从任何组件全局访问 Apollo。
  • import { ApolloProvider } from '@apollo/react-hooks'
    import { useApollo } from '../lib/apollo/apolloClient'

    /**
    * <MyApp>
    *
    * This is an override of the default _app.js setup Next.js uses
    *
    * <ApolloProvider> gives components global access to GraphQL data fetched in the components (like menus)
    *
    */
    const MyApp = ({ Component, pageProps }) => {
    // Instantiates Apollo client, reads Next.js props and initialized Apollo with them - this caches data into Apollo.
    const apolloClient = useApollo(pageProps.initialApolloState)

    return (
    <ApolloProvider client={ apolloClient }>
    <Component {...pageProps} />
    </ApolloProvider>
    )
    }

    export default MyApp
    现在您可以使用 Apollo 获取组件内部的动态数据!很容易吧 ;) 哈!

    关于javascript - Next.js 在组件内获取数据的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63494479/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com