【问题标题】:How to dispatch action when a state changes in redux toolkit without using useEffect?如何在不使用 useEffect 的情况下在 redux 工具包中的状态更改时调度操作?
【发布时间】:2022-01-20 00:04:43
【问题描述】:

如果我想在状态发生变化时分派一个动作,目前我的做法是通过在组件useEffect 挂钩中监听该状态并在该状态发生变化时分派一个动作。

例如,假设我有以下切片:

export const updateBar = createAsyncThunk("mySlice/updateBar", async () => {
  const { data } = await axios.get("/some/api");
  return data;
});

const mySlice = createSlice({
  name: "mySlice",
  initialState: {
    foo: false,
    bar: 0,
  },
  reducers: {
    updateFoo: (state, { payload }) => {
      state.foo = payload;
    },
  },
  extraReducers: {
    [updateBar.fulfilled]: (state, { payload }) => {
      state.bar = payload;
    },
  },
});

现在如果我想在foo发生变化时更新bar,我必须去组件端添加以下代码:

const Component = () => {
  const foo = useSelector((state) => state.mySlice.foo);

  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(updateBar());
  }, [dispatch, foo]);

  return <div></div>;
};

我想知道当foo 在redux 切片中发生变化时是否可以调用updateBar 而不必触及组件端,因为我认为如果将所有状态副作用都从组件。

【问题讨论】:

标签: javascript reactjs redux react-redux redux-toolkit


【解决方案1】:

一种解决方案是创建另一个 thunk 来封装两个更新操作。我们在这个 thunk 中执行 update foo 操作,并使用 thunkAPI 来调度更新栏操作。

当您只想更新 foo 时,我们可以继续保持 updateFoo 操作。

Thunk 帮助我们封装动作的逻辑。比如action什么时候派发,什么action派发,以及它们之间的关系,串行dispatch还是并发dispatch。

例如

//@ts-nocheck
import { createAsyncThunk, createSlice, configureStore } from '@reduxjs/toolkit';

const mockApi = async () => {
  return { data: 100 };
};

export const updateBar = createAsyncThunk('mySlice/updateBar', async () => {
  const { data } = await mockApi();
  return data;
});

export const updateFooWithBar = createAsyncThunk('mySlice/updateFooWithBar', (arg, thunkAPI) => {

  // If bar depends on foo state or other state, 
  // you can use thunkAPI.getState() to get the whole state, pick what you need.
  thunkAPI.dispatch(updateBar());
  return arg;
});

const mySlice = createSlice({
  name: 'mySlice',
  initialState: {
    foo: false,
    bar: 0,
  },
  reducers: {
    updateFoo: (state, { payload }) => {
      state.foo = payload;
    },
  },
  extraReducers: {
    [updateBar.fulfilled]: (state, { payload }) => {
      state.bar = payload;
    },
    [updateFooWithBar.fulfilled]: (state, { payload }) => {
      state.foo = payload;
    },
  },
});

const store = configureStore({ reducer: mySlice.reducer });
store.subscribe(() => {
  console.log(store.getState());
});
store.dispatch(updateFooWithBar('next foo')).then(() => {
  store.dispatch(mySlice.actions.updateFoo('next next foo'));
});

执行结果:

{ foo: false, bar: 0 }
{ foo: false, bar: 0 }
{ foo: 'next foo', bar: 0 }
{ foo: 'next foo', bar: 100 }
{ foo: 'next next foo', bar: 100 }

【讨论】:

  • 感谢您的建议。但是,如果我有多个更新 foo 的操作怎么办?例如,如果 foo 是一个数组,并且我有 addToFoo、removeFromFoo、clearFoo 等操作。那么我需要记住在更新 foo 的每个操作中调用 dispatch(updateBar()) ,否则它可能会引入潜在的困难- 发现错误。
猜你喜欢
  • 2016-05-26
  • 2017-07-20
  • 2018-10-29
  • 2022-12-30
  • 2023-03-31
  • 2016-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多