[英]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 时发生。
我尝试在呈现页面之前填充数据,但getInitialProps
和setStaticProps
仅适用于页面。
更新按照我在这个线程中找到的指示,我进行了下一次更新:
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
是属性,我将它传递给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 文档,我更改了获取 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.