跳转到内容

Next.js

Jotai 通过 useHydrateAtoms 支持原子的水合。相关文档请参见这里

可以将 Jotai 与路由同步。你可以通过 atomWithHash 实现:

const pageAtom = atomWithHash('page', 1, {
replaceState: true,
subscribe: (callback) => {
Router.events.on('routeChangeComplete', callback)
window.addEventListener('hashchange', callback)
return () => {
Router.events.off('routeChangeComplete', callback)
window.removeEventListener('hashchange', callback)
}
},
})

这样你就能完全控制要订阅哪个路由事件

从 Next.js 13 开始,Router.events.on() 发生了变化,不再暴露事件。App Router Roadmap 中计划了事件拦截和 hash 处理,但目前没有具体的时间表或实现方式。目前使用 atomWithHash() 时,通过路由导航不会在原子中加载数据,只有在页面重新加载或组件重新渲染时才会生效。建议将 setHash 选项设置为 replaceState,因为 Next.js 在底层似乎使用了 window.history,这样可以让用户使用浏览器的后退按钮。

服务端渲染(SSR)中不能返回 promise

Section titled “服务端渲染(SSR)中不能返回 promise”

需要注意的是,在服务端渲染(SSR)中不能返回 promise。不过,你可以在原子定义中进行防护处理。

如果可能,请使用 useHydrateAtoms 从服务端水合值。

const postData = atom((get) => {
const id = get(postId)
if (isSSR || prefetchedPostData[id]) {
return prefetchedPostData[id] || EMPTY_POST_DATA
}
return fetchData(id) // returns a promise
})

默认情况下,Jotai 使用一个隐式的全局 store 来追踪原子的值。这就是所谓的”无 Provider”模式。在服务端渲染(SSR)场景中这会成为问题,因为全局 store 会持续存在并在多个请求之间共享,这可能导致 bug 和安全风险。

为了将 store 的生命周期限制在单个请求的范围内,你需要在应用的根部(或使用 Jotai 的子树根部)使用 Provider

import { Provider } from 'jotai'
function App({ Component, pageProps }: AppProps) {
return (
<Provider>
<Component {...pageProps} />
</Provider>
)
}

在这种情况下:

  1. Provider 会将其子树中使用的原子状态保存在自身而非全局 store 中。
  2. Provider 的生命周期与应用一致,由于每次 SSR 请求都会重新创建应用,我们实际上将 store 的生命周期限制在了单个请求内。

Jotai 提供了 SWC 插件,以改善使用 Next.js 开发时的体验。在 SWC 章节了解更多信息。

在 StackBlitz 中打开

Page Router 示例:

在 StackBlitz 中打开

App Router 在 Stackblitz 上的示例

Terminal window
npx create-next-app --example with-jotai with-jotai-app

这是链接