Next.js 获取并维护所有组件的全局数据
Next.js Fetch and Maintain global data for all components
在我的 Next.js 应用程序中,我需要进行 API 调用,该调用将 return 一个 JSON 响应,所有组件都需要使用该响应。因此,我将避免在我的组件中多次调用相同的 API。实现这一目标的正确方法是什么?
使用 redux 将您的状态存储在全局存储中,以便多个组件可以访问它,这是您的用例类型的常见模式。
它也有 next-wrapper
这是 link next-redux-wrapper redux
取决于应用范围。
如果它很大,您可能应该采用像 Redux 这样的状态管理器,正如 Moshin Amjad 所说。
如果它是一个较小的应用程序,您可以尝试使用 React 上下文 API 来管理它。
我将以最简单的方式举个例子,使用功能组件,利用 getStaticProps
而不是 getInitialProps
来获取静态生成的页面。
开始创建简单的上下文
libs/context.js
import React from "react";
export const Context = React.createContext();
然后用来自 getStaticProps(或 getInitialProps)的数据填充一个 useState
钩子(或者更好,一个 useReducer
取决于数据的结构),然后将它传递给 Context Provider .
pages/index.js
import React from 'react'
import { Context } from "../libs/context.js"
import Title from "../components/Title"
import Button from "../components/Button"
// data will be populated at build time by getStaticProps()
function Page({ data }) {
const [ context, setContext ] = React.useState(data)
return (
<Context.Provider value={[context, setContext]}>
<main>
<Title />
<Button />
</main>
</Context.Provider>
)
}
export async function getStaticProps(context) {
// fetch data here
const data = await fetchData()
// Let's assume something silly like this:
// {
// buttonLabel: 'Click me to change the title',
// pageTitle: 'My page'
// }
return {
props: {
data
}, // will be passed to the page component as props
}
}
最后在提供者的任何 child 中使用它(或更改它!)。
components/Title.js
import React, { useContext } from "react"
import { Context } from "./Context"
export default function MyComponent() {
const [context, setContext] = useContext(Context)
return (
<h1>{context.pageTitle}</h1>
)
}
components/Button.js
import React, { useContext } from "react"
import { Context } from "./Context"
export default function MyComponent() {
const [context, setContext] = useContext(Context)
function changeTitle() {
preventDefault();
setContext(oldContext => ({
...oldContext,
pageTitle: 'New page title!'
}))
}
return (
<div>
<button onClick={changeTitle}>{context.buttonLabel}</button>
</div>
)
}
它未经测试,但你明白了。
最终,您可以将上下文提供程序移动到高阶组件中以包装每个页面,如果您需要更高级别的数据,甚至可以在 pages/_app.js
中移动。
记住,如果应用扩展,你应该考虑像 Redux 这样的东西。
在我的 Next.js 应用程序中,我需要进行 API 调用,该调用将 return 一个 JSON 响应,所有组件都需要使用该响应。因此,我将避免在我的组件中多次调用相同的 API。实现这一目标的正确方法是什么?
使用 redux 将您的状态存储在全局存储中,以便多个组件可以访问它,这是您的用例类型的常见模式。 它也有 next-wrapper 这是 link next-redux-wrapper redux
取决于应用范围。
如果它很大,您可能应该采用像 Redux 这样的状态管理器,正如 Moshin Amjad 所说。
如果它是一个较小的应用程序,您可以尝试使用 React 上下文 API 来管理它。
我将以最简单的方式举个例子,使用功能组件,利用 getStaticProps
而不是 getInitialProps
来获取静态生成的页面。
开始创建简单的上下文
libs/context.js
import React from "react";
export const Context = React.createContext();
然后用来自 getStaticProps(或 getInitialProps)的数据填充一个 useState
钩子(或者更好,一个 useReducer
取决于数据的结构),然后将它传递给 Context Provider .
pages/index.js
import React from 'react'
import { Context } from "../libs/context.js"
import Title from "../components/Title"
import Button from "../components/Button"
// data will be populated at build time by getStaticProps()
function Page({ data }) {
const [ context, setContext ] = React.useState(data)
return (
<Context.Provider value={[context, setContext]}>
<main>
<Title />
<Button />
</main>
</Context.Provider>
)
}
export async function getStaticProps(context) {
// fetch data here
const data = await fetchData()
// Let's assume something silly like this:
// {
// buttonLabel: 'Click me to change the title',
// pageTitle: 'My page'
// }
return {
props: {
data
}, // will be passed to the page component as props
}
}
最后在提供者的任何 child 中使用它(或更改它!)。
components/Title.js
import React, { useContext } from "react"
import { Context } from "./Context"
export default function MyComponent() {
const [context, setContext] = useContext(Context)
return (
<h1>{context.pageTitle}</h1>
)
}
components/Button.js
import React, { useContext } from "react"
import { Context } from "./Context"
export default function MyComponent() {
const [context, setContext] = useContext(Context)
function changeTitle() {
preventDefault();
setContext(oldContext => ({
...oldContext,
pageTitle: 'New page title!'
}))
}
return (
<div>
<button onClick={changeTitle}>{context.buttonLabel}</button>
</div>
)
}
它未经测试,但你明白了。
最终,您可以将上下文提供程序移动到高阶组件中以包装每个页面,如果您需要更高级别的数据,甚至可以在 pages/_app.js
中移动。
记住,如果应用扩展,你应该考虑像 Redux 这样的东西。