Jotai状态管理实战经验与性能优化技巧分享
又踩坑了,Jotai 的异步状态管理让我头大
最近在用 Jotai 做一个项目的状态管理,本来觉得这东西简单好用,结果在处理异步数据的时候踩了个大坑。折腾了半天才发现问题出在哪。
场景是这样的:我需要从 https://jztheme.com/api/data 拉取一些数据,然后把数据存到 atom 里供组件使用。听起来挺简单的对吧?但问题就出在异步这块。
核心代码就这几行,但一开始完全跑不通
我最初写的代码大概是这样的:
import { atom, useAtom } from 'jotai';
const dataAtom = atom(async () => {
const res = await fetch('https://jztheme.com/api/data');
return res.json();
});
function DataComponent() {
const [data] = useAtom(dataAtom);
if (data instanceof Promise) {
return <div>加载中...</div>;
}
return (
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
这里我踩了个坑,以为直接在 atom 定义里写 async 就能搞定异步逻辑。结果页面一直显示“加载中…”,根本没渲染出实际数据。
排查过程:试了三种方法才找到正解
一开始我以为是 API 的问题,跑去 Postman 测试了一下接口,发现返回的数据是正常的。这就排除了后端的问题。
后来试了下把 async 放到组件内部:
const dataAtom = atom(null);
function DataComponent() {
const [data, setData] = useAtom(dataAtom);
useEffect(() => {
fetch('https://jztheme.com/api/data')
.then(res => res.json())
.then(setData);
}, [setData]);
if (!data) {
return <div>加载中...</div>;
}
return (
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
这个方案倒是能跑通,但总觉得不够优雅。而且如果多个组件都需要用这个数据,就得重复写这些逻辑。
最终解决方案:atomWithDefault + atomWithQuery
最后还是得感谢社区,找到了一个更合适的解决方案。Jotai 提供了一个叫 atomWithDefault 的工具,配合自定义的异步处理特别好用。
完整代码如下:
“javascript
import { atom, useAtom, atomWithDefault } from 'jotai';
import { atomWithQuery } from 'jotai/query';
const fetchData = async () => {
const res = await fetch('https://jztheme.com/api/data');
if (!res.ok) throw new Error('Failed to fetch data');
return res.json();
};
const dataAtom = atomWithDefault(async get => {
return fetchData();
});
function DataComponent() {
const [data, setData] = useAtom(dataAtom);
if (data instanceof Promise) {
data.then(setData).catch(err => console.error(err));
return <div>加载中...</div>;
}
return (
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
`>
这里有几个关键点要注意:
- atomWithDefault 可以让 atom 在初始化时执行异步函数
- 记得处理异常情况,否则某个请求失败可能导致整个应用崩溃
- 在组件里要判断返回值是否是 Promise,避免直接渲染未解析的数据
技术细节补充:为什么第一种写法会出问题
回过头来看最初的写法,问题出在 Jotai 的 atom 设计上。atom 本质上是一个同步的状态容器,虽然你可以传入一个返回 Promise 的函数,但它不会自动帮你处理异步逻辑。
换句话说,当你在 atom 定义里写了 async 函数,返回的其实是一个 Promise 对象,而不是实际的数据。所以组件拿到的始终是个 Promise,自然没法正常渲染。
踩坑提醒:这三点一定注意
总结一下这次踩坑的经验,有几点需要注意:
- Jotai 的 atom 默认是同步的,异步逻辑需要额外处理
- 不要直接在组件里写 fetch 逻辑,尽量封装到 atom 层
- 记得处理异常情况,比如网络错误或数据格式不对
虽然改完之后还有个小问题——首次加载时会有短暂的闪烁(因为先显示“加载中…”再渲染数据),但整体效果已经可以接受了。如果你有更好的优化方案,欢迎评论区交流!
以上是我踩坑后的总结,希望对你有帮助。后续我会继续分享一些 Jotai 的实战经验,尤其是复杂状态管理的场景。

暂无评论