NextJS 中每个组件的共享/获取数据
Posted
技术标签:
【中文标题】NextJS 中每个组件的共享/获取数据【英文标题】:Sharing/Fetching data per component in NextJS 【发布时间】:2020-11-06 10:57:39 【问题描述】:我正在尝试从我的模型中获取一些数据,使用 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
很简单。
我从 navbar 组件调用这个函数:
export async function getLocalizedTitle(slug)
const data = await getPageTitleBySlug(slug)
return ...data?.pages[0]
这个函数在组件内部调用:
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>
))
不幸的是,每次我调用此函数或刷新站点时,我都会得到:
很容易意识到问题出在 fetch 中,但它只是在我从组件调用 fetch 时发生。
我尝试在渲染页面之前填充数据,但 getInitialProps
和 setStaticProps
仅适用于页面。
更新 按照我在thread 中找到的指示,我进行了下一次更新:
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
值,调用该函数一次。
后来,我将此字典作为默认属性传递给_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
是属性,我将它传递给footer
和nav
。当页面确实存在时,它大部分时间都可以工作;但是,当我们收到 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 documentation,我更改了我的获取功能,我重新制作了该功能以获取所有数据,然后将其传递给属性。
它解决了渲染菜单的问题,但它没有解决我使用Promise.all
和获取解决方案时遇到的下一个问题:
如您所见,每次我进入索引页面时,都会遇到该错误,这是因为它使用localhost:3000/undefined/graphql
获取而不是localhost:1337/graphql
,默认情况下设置为process.env.API_URL
,如process.env.API_URL
;当我从每个页面重定向到 Home(index) 时,就会发生这种情况,有时会出现 404 或 500 错误。
我不是很明白。
我该如何处理?
谢谢。
【问题讨论】:
【参考方案1】:酷,终于,我们可以用下一个方法来处理它了。
首先,看一下post主页面的NextJS示例,我们可以发现它使用了一个获取帖子和另一个附加帖子的函数;深入了解function,我们可以看到它只是 fetch 用于获取整个数据:它不是使用不同的 fetch 函数逐部分获取数据,而是使用 GraphQL 查询获取所有需要的数据。
按照这种方式,我们重构我们的函数以获取单个对象中的全名作为获取响应:
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
到filter 任何字段匹配数组值的对象;因此,将 navLinks
中的 slug 作为字典传递,我们可以获得所有与想要的 slug 匹配的页面:
const navProps = await getPageTitlesBySlugSet(menu_links.map(( label ) => label))
酷,现在我们可以以更简单的方式一次获取所有数据。酷,现在我们可以将navProps
作为属性传递给页脚和导航组件,我们将对其进行处理以本地化它们:
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 获取,但它只能从服务器访问,它是不为客户公开;因此,它无法正确获取,给我们一个错误。
如何解决?同样,在documentation 中它说我们必须使用NEXT_PUBLIC_
作为每个变量的前缀,我们也可以从客户端访问这些变量。所以,我们把它放进去,它解决了我们的问题,现在我们可以从网站的每个页面导航到索引页面。
就是这样。
还有一个时间慢的问题,我们稍后会处理。
【讨论】:
以上是关于NextJS 中每个组件的共享/获取数据的主要内容,如果未能解决你的问题,请参考以下文章
react-query 在 nextjs 中重新获取页面更改的数据
无法在 NextJS React 组件中获取背景图像渲染 [已解决但无法解释]