繁体   English   中英

NextJS 中每个组件的共享/获取数据

[英]Sharing/Fetching data per component in NextJS

我正在尝试使用GraphQL从我的模型中获取一些数据,以便通过本地化语言动态预填充导航栏:

export async function getPageTitleBySlug(slug) {
  const data = await fetchAPI(
    `query PageTitleBySlug($where: JSON){
      pages(where: $where) {
        title_en
        title {
          title_es
          title_tr
        }
      }
    }`,
    {
      variables: {
        where: { slug },
      },
    }
  )

  return data
}

很容易。

我将导航栏组件中的 function 称为:


export async function getLocalizedTitle(slug) {
  const data = await getPageTitleBySlug(slug)
  return { ...data?.pages[0] }
}

这个 function 在组件内部被调用:

  const [labels, setLabels] = useState(links.map(({ label }) => ({ [label]: "" })))

  useEffect(() => {
    links.map(async ({ label }) => {
      const { title, title_en } = await getLocalizedTitle(label)

      const localizedTitle =
        title[
          Object.keys(title).find(
            (content) => content.split("_")[1] == i18n.language
          )
        ] || title_en
      setLabels({ [label]: localizedTitle })
    })
  }, [i18n.language])

它确实有效,因为每次我更改本地语言时,都会调用此效果。

我的想法是从这本字典中获取价值:

        {links.map(({ key, href, label }) => (
          <MenuItem key={key}>
            <Link href={href}>
              <a></a>
            </Link>
          </MenuItem>
        ))}

不幸的是,每次我调用这个 function 或刷新我得到的网站: 在此处输入图像描述

很容易意识到问题出在 fetch 中,但它只是在我从组件调用 fetch 时发生。

我尝试在呈现页面之前填充数据,但getInitialPropssetStaticProps仅适用于页面。

更新按照我在这个线程中找到的指示,我进行了下一次更新:

FolioApp.getInitialProps = async (appContext) => {
  const appProps = await App.getInitialProps(appContext)

  // TODO: Here at beginning is undefined, so, i'm getting errors in console, it should be a defaultProp, but how?
  let navProps = {}
  menu_links.map(async ({ label }) => {
    const { title, title_en } = await getLocalizedTitle(label)
    navProps[label] = { title, title_en }
  })

  const defaultProps = appContext.Component.defaultProps

  return {
    ...appProps,
    navProps,
    pageProps: {
      namespacesRequired: [
        ...(appProps.pageProps.namespacesRequired || []),
        ...(defaultProps?.i18nNamespaces || []),
      ],
    },
  }
}

我的目标是得到一个字典,其中包含标题(一个对象)和数组中所有链接的title_en值,调用 function 一次。 稍后,我将此字典作为默认属性传递给_app组件:

const FolioApp = ({ Component, pageProps, navProps }) => {
  useEffect(() => {
    // Remove the server-side injected CSS.
    const jssStyle = document.querySelector("#jss-server-side")

    if (jssStyle) {
      jssStyle.parentElement.removeChild(jssStyle)
    }
  }, [])

  return (
    <>
      <Meta />
      <DefaultSeo
        {...DefaultSEO}
        additionalMetaTags={[
          {
            name: "msapplication-TileColor",
            content: CMS_TILE_COLOR,
          },
          {
            name: "msapplication-config",
            content: "/favicon/browserconfig.xml",
          },
        ]}
      />
      {/* TODO: Add a proper theme */}
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <Nav navLinks={navProps} />
        <Component {...pageProps} />
        <Footer navLinks={navProps} />
      </ThemeProvider>
    </>
  )
}

navLinks是属性,我将它传递给footernav 它在页面确实存在的大部分时间都有效; 但是,当我们收到404错误页面甚至在索引中时,它都不起作用: 在此处输入图像描述

我在错误或索引页面中得到一个空的navLinks 为什么?

更新:现在,我尝试使用Promise.all解决它,以便在将所有获取的数据加入一次之前将其传递给道具:

await Promise.all(
    menu_links.map(async ({ label }) => {
      const { title, title_en } = await getLocalizedTitle(label)
      navProps[label] = { title, title_en }
    })
  )

它确实有效,但我不太喜欢这个解决方案。

我搜索了cms-strapi示例,发现它从一次提取中获取全部数据,这是最好的,因为getInitialProps只执行一次,并且比为每种不同类型的所需数据单独提取更好。

因此,由于strapi 文档,我更改了获取 function 的方法,我重新制作了 function 以获取所有数据,然后将其传递给属性。

它解决了渲染菜单的问题,但没有解决我使用Promise.all和获取解决方案时遇到的下一个问题: 在此处输入图像描述

正如你所看到的,每次我 go 到索引页面时,我都会遇到那个错误,它发生是因为它使用localhost:3000/undefined/graphql而不是localhost:1337/graphql ,它被解决为process.env.API_URL默认为process.env.API_URL 当我从每个页面重定向到主页(索引)时,就会发生这种情况,有时会出现 404 或 500 错误。

我不太明白。

我该如何处理?

谢谢你。

酷,终于,我们可以用下一种方式处理它。

首先,看一下主要帖子页面的NextJS示例,我们可以意识到它使用 function 来获取帖子和另一个附加帖子; 深入研究这个function ,我们可以看到它只是为获取整个数据而获取:它不是使用不同的获取 function 逐个获取数据,而是使用Z524DE3D2ADE45344176F60702查询来获取所需的数据。

按照这种方式,我们重构我们的 function 以获取单个 object 中的全名作为获取响应:

export async function getPageTitlesBySlugSet(slugSet) {
  const data = await fetchAPI(
    `query PageTitleBySlug($where: JSON){
      pages(where: $where) {
        slug
        title_en
        title {
          title_es
          title_tr
        }
      }
    }`,
    {
      variables: {
        where: { slug_in: slugSet },
      },
    }
  )

  return data?.pages
}

这个想法是让所有页面都存在navLinks中的 slug,但是如何? 我们可以直接考虑使用过滤器(作为GraphQL功能),但是在Strapi的 GraphQL 控制台中测试它,我们看不到过滤器选项; 我们能做什么? 阅读文档,有效地,我们可以使用field_in 过滤任何 object 字段在数组值中匹配; 因此,将navLinks中的 slug 作为字典传递,我们可以获得与所需 slug 匹配的所有页面:

const navProps = await getPageTitlesBySlugSet(menu_links.map(({ label }) => label))

很酷,现在我们可以以更简单的方式一次获取所有数据。 很酷,现在我们可以将navProps作为属性传递给 footer 和 nav 组件,我们将对其进行处理以本地化它们:

{navLinks &&
                Object.keys(navLinks).length !== 0 &&
                menu_links.map(({ key, href, label }) => (
                  <Link href={href} key={key} passHref>
                    <MenuItem>{localizedTitle(label)}</MenuItem>
                  </Link>
                ))}

很酷,但这里仍然有一个问题:有时访问索引会给我们带来问题,因为它尝试使用API URL 获取,但它只能从服务器访问,它对客户端不公开; 因此,它无法正确获取,给我们一个错误。

如何解决? 同样,在文档中它说我们必须使用NEXT_PUBLIC_作为我们希望也可以从客户端访问的每个变量的前缀。 所以,我们放了它,它解决了我们的问题,现在我们可以从网站的每个页面导航到索引页面。

就这样。

还有一个时间慢的问题,我们稍后会处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM