【问题标题】:Reducer gets called in unexpected way - Redux SagaReducer 以意想不到的方式被调用 - Redux Saga
【发布时间】:2021-05-09 02:39:31
【问题描述】:

嘿,我遇到了一个小问题,正在尝试制作小型 todo 应用程序。错误显示在浏览器的控制台中,UI 没有中断,但它让我抓狂,因为我想知道为什么会这样?

我用它的参数调用 setChecked 的主要组件,要检查的项目的 id 和 checkValue(true 或 false)。

import { useSelector, useDispatch } from "react-redux";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Checkbox from "@material-ui/core/Checkbox";
import { setChecked } from "../redux/actions/todoActions";

export default function Main() {
  const tasks = useSelector((state) => state.todoReducer.tasks);
  const dispatch = useDispatch();

  const taskItems = Array.from(tasks).map((item, index) => {
    return item.checked !== true && item.date ? (
      <div
        key={index}
        className="item-row"
        onClick={() => dispatch(setChecked(item.id, !item.checked))}
      >
        <label className="check-flag">
          <span className="check-flag-label">{item.title}</span>
          <FormControlLabel
            className="checkbox"
            control={
              <Checkbox className="checkbox-native" checked={item.checked} />
            }
          ></FormControlLabel>
        </label>
      </div>
    ) : (
      ""
    );
  });

  return (
    <main className="main">
      <div className="wrap">{taskItems}</div>
    </main>
  );
}

setChecked 操作

const setChecked = (id, checked) => ({
  type: TODO.SET_CHECKED,
  itemToChange: { id, checked },
});

tod​​oSaga

function* handleGetTodo(action) {
  yield put({ type: TODO.GET_TODO });
}

function* handleSetChecked(action) {
  yield put({ type: TODO.SET_CHECKED, action });
}

export default function* watchTodo(action) {
  yield takeEvery(TODO.GET_TODO, handleGetTodo);

  yield takeLatest(TODO.SET_CHECKED, handleSetChecked);
}

减速器

const todoReducer = (state = initialState, action) => {
  switch (action.type) {
    case TODO.GET_TODO:
      return { ...state };
    case TODO.SET_CHECKED:
      var tasks = state.tasks;

      tasks = tasks.map((item) => {
        if (item.id === action.itemToChange.id) {
          return { ...item, checked: action.itemToChange.checked };
        }

        return { ...item };
      });

      return { ...state, tasks: tasks };

    default:
      return { ...state };
  }
};

First call - this is ok

Second call - whole action gets passed to action so now i have action.action.itemToChange

我正在使用 React.StrictMode 并且我知道它必须调用某些函数两次,这不是问题,但为什么他在动作对象本身内部制作嵌套动作对象?我希望我能成功地表达自己。

感谢您的宝贵时间

【问题讨论】:

  • Re:奇怪的属性名称,这就是 redux-saga 在幕后的工作方式。它是一个中间件,因此它知道如何处理看起来像这样的动作。向下滚动到 API 文档中的“actionDispatched(action)”部分redux-saga.js.org/docs/api
  • action : Object - 调度的 Redux 操作。如果 action 是由 Saga 调度的,那么该 action 的属性 SAGA_ACTION 将设置为 true(SAGA_ACTION 可以从 @redux-saga/symbols 导入)。
  • Re: 嵌套动作,这是因为你在 handleSetChecked 中创建的动作。 yield put({ type: TODO.SET_CHECKED, action }) — 您将整个操作传递给属性操作。

标签: reactjs redux redux-saga reducers


【解决方案1】:

现在,您的 saga 没有任何意义,因为您正在执行一个操作,然后发送基本相同的操作。事实上,这样做可能会造成无限循环。

您在由 redux-saga 创建的操作版本中获得嵌套操作的原因是由于您在 handleSetChecked 函数中创建操作的方式。它接收一个参数action,它是被take 截获的整个动作对象。然后它使用put 调度一个看起来像yield put({ type: TODO.SET_CHECKED, action }); 的新动作,该动作具有typeaction 属性,其中action 是整个原始动作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-03
    • 1970-01-01
    • 2019-12-05
    • 1970-01-01
    • 2019-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多