我正在尝试使用GraphQL
从模型中获取一些数据,以便通过本地化语言动态地预先填充Navbar:
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>
))}
很容易意识到问题出在提取中,但这只是在我从组件调用提取时发生的。
我试图在渲染页面之前填充数据,但是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
来解决它,以便将所有提取的数据连接一次,然后再传递给props:
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
来获取的,而{{1} }}默认为process.env.API_URL
;当我从每个页面重定向到首页(索引)时,有时甚至在出现404或500错误时,都会发生这种情况。
我不太了解。
我该如何处理?
谢谢。
答案 0 :(得分:0)
很酷,最后,我们可以用另一种方式来处理它。
首先,查看post主页上的 NextJS 示例,我们可以意识到它正在使用获取帖子和其他帖子的功能;深入研究function,我们可以看到它只是用于获取全部数据的获取:它不是使用不同的获取功能来部分获取数据,而是使用 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
中存在的子页的页面,但是如何?我们可以直接考虑使用过滤器(作为 GraphQL 功能),但是在 Strapi 的GraphQL控制台中对其进行测试,我们看不到文件管理器选项。我们能做些什么?有效地阅读文档,我们可以使用field_in
来filter任何字段匹配数组值的对象;因此,通过将navLinks
的子弹作为字典传递,我们可以获得与所需子弹匹配的所有页面:
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_
用作每个我们也希望可以从客户端访问的变量的前缀。因此,我们放置它并解决了我们的问题,现在我们可以从站点中的每个页面导航到索引页面。
仅此而已。
仍然存在速度较慢的问题,我们稍后会处理。