Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
232 views
in Technique[技术] by (71.8m points)

reactjs - Reducer gets called in unexpected way - Redux Saga

Hey there I am having a minor issue, trying to make small todo application. The error shows in the console of a browser, UI doesn't breaks but it drives me nuts because I want to know why is this happening?

Main component where I am calling setChecked with it's arguments, id of an item to be checked and checkedValue(true or 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 action

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

todoSaga

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);
}

reducer

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

I am using React.StrictMode and I understand it has to calls some functions twice which isn't a problem but why does he makes nested action object inside of action object itself? I hope that I am expressing myself successfully.

Thank you for your time

question from:https://stackoverflow.com/questions/66051679/reducer-gets-called-in-unexpected-way-redux-saga

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Right now your saga serves no purpose because you are taking an action and then dispatching essentially the same action. In fact you might be creating an infinite loop by doing this.

The reason that you get a nested action in the version of your action which is created by redux-saga is due to how you are creating the action in your handleSetChecked function. It receives an argument action which is the entire action object that was intercepted by take. It then uses put to dispatch a new action which looks like yield put({ type: TODO.SET_CHECKED, action }); That action has properties type and action, where action is the entire original action.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...