Easy Peasy 中如何正确监听 store 变化并触发副作用?

欧阳丽丽 阅读 77

我在用 Easy Peasy 做一个 React 项目,想在某个状态更新后自动执行一个副作用(比如发请求),但发现直接在组件里 useEffect 监听 store 状态好像没反应。

我试过这样写:useEffect(() => { fetchData(); }, [store.someValue]),但 someValue 更新后副作用没触发。是不是得用 Easy Peasy 提供的监听机制?

看到文档里有 onAction 和 thunk,但不太清楚具体怎么用。比如我想在 user.id 变更时重新拉取用户详情,该怎么写?

const store = createStore({
  user: {
    id: null,
    profile: {},
    setId: action((state, payload) => {
      state.id = payload;
    }),
    // 这里怎么加监听逻辑?
  }
});
我来解答 赞 12 收藏
二维码
手机扫码查看
2 条解答
东方莉娟
在Easy Peasy里直接useEffect监听store确实不靠谱,性能上也不合理。正确姿势是用它的effectAPI,这个就是专门用来处理副作用的。

给你改下代码,比如要在id变更时拉取用户详情:

const store = createStore({
user: {
id: null,
profile: {},
setId: action((state, payload) => {
state.id = payload;
}),
fetchProfile: thunk(async (actions, payload, { getState }) => {
const res = await fetch(/user/${getState().user.id});
actions.setProfile(await res.json());
}),
setProfile: action((state, payload) => {
state.profile = payload;
})
}
}, {
effects: {
user: {
// 关键在这里!监听id变化自动触发fetchProfile
setId: effect((actions, payload) => {
actions.user.fetchProfile();
})
}
}
});


要点:
1. 在effects里定义副作用逻辑
2. 当setId这个action执行完,会自动触发对应的effect
3. 然后在effect里调用thunk发起请求

这样比useEffect监听干净多了,也不会产生多余的渲染。顺便说下,如果请求有竞态问题记得加abort controller,不过那是另一回事了。
点赞 2
2026-03-07 08:00
爱学习的芹芹
我血泪教训告诉你,别在组件里用 useEffect 直接监听 Easy Peasy store 的状态,它根本不会触发重新渲染,因为 Easy Peasy 是基于 immer 的,内部状态变更不会触发 React 的 diff,你监听的 store.someValue 可能是个代理对象引用,永远不变。

要实现「状态变更后自动触发副作用」,正确姿势是用 thunk,别用 onAction(那个更适合日志、埋点这类通用逻辑,不适合业务副作用)。

你这个场景,应该这样写:

const store = createStore({
user: {
id: null,
profile: {},
setId: action((state, payload) => {
state.id = payload;
}),
fetchProfile: thunk(async (actions, payload, { getStoreState }) => {
const currentId = getStoreState().user.id;
if (!currentId) return;
const res = await fetch(/api/user/${currentId});
const data = await res.json();
actions.setProfile(data);
}),
setProfile: action((state, payload) => {
state.profile = payload;
})
}
});


然后在组件里这样用:

const { user, setUser } = useStoreState(state => ({ user: state.user }));
const { fetchProfile } = useStoreActions(actions => actions.user);

useEffect(() => {
if (user.id) {
fetchProfile();
}
}, [user.id, fetchProfile]);


注意!这里 useEffect 里监听的是 user.id,但这个 user 是你从 store 里用 useStoreState 选出来的,Easy Peasy 会把选中的字段做 shallow compare,变了就会触发 effect。

我当初就踩过坑,直接用 store.user.id 当依赖,结果依赖数组永远是同一个代理对象,effect 根本不跑。记住:监听必须用 useStoreState 提供的值,不能直接用 store 实例。

还有一种更骚的操作是用 onAction + thunk 组合,但容易死循环,不推荐:

const store = createStore({
user: { ... },
onAction: action((state, payload) => {
if (payload.type === 'user/setId') {
// 别在这直接发请求!会卡死!
// 正确做法是 dispatch 一个 thunk
store.dispatch.user.fetchProfile(); // 这里会报错!store 没定义
}
})
}, {
middleware: thunk.withExtraArgument(() => store) // 这种写法也容易崩
});


真要这么写得用 createStore 的第二个参数传 middleware,但太绕,容易把自己绕进去。还是前面那种在组件里用 useEffect + useStoreActions 最稳妥,清晰好调试,别图省事。
点赞 7
2026-02-25 09:17