@aleks_web_dev

Reducer вызывается по 2 раза в useReducer?

У меня есть простейшие приложение todo .
Проблема во в чем: reducer вызывается 2 раза . В каждом todo item есть чекбокс по клику на него значение checked меняться на противоположное но из-за того что это происходит 2 раза , оно остается таким же как и было . До useReducer все работало хорошо .
Пробовал вызывать dispatch.bind(null,action) не помогло , заменял onChange на onClick нечего не дало
Action 'add' и 'del' работаю , тоже вызываются по 2 раза но в DOM все верно отображается .
Серавно не могу понять почему вызывается по 2 раза reducer .

Доки читал видео смотрел , скопировал счечик с оф.сайта там тоже reducer вызывался оп 2 раза
Использую только useReducer , без redux

App.js
import React, { useState, useEffect, useReducer } from "react";
import TodoList from "./TodoList";

export const ContextApp = React.createContext();

const reducer =(state,action)=>{
  console.log('reducer')
  switch (action.type) {
    case 'add':
      console.log('add')
        return [
          ...state,
          {
            id: new Date()+Math.random(),
            title: action.title,
            desc: action.text,
            checked: false,
          }
        ]
    case 'checked':
      return state.map(item=>{
          if(item.id === action.id){
            item.checked = !item.checked;
          }
          return item;
        })
    case 'del':
      return state.filter(item=>item.id!==action.id)
    default:
      return state
  }
}

function App() {
  const [state, dispatch] = useReducer(reducer, [])

  const [todoValue, setValue] = useState({
    input: "",
    text: "",
  });
  useEffect(()=>{
    console.log(state);
  },[state])

  return (
    <ContextApp.Provider value={{dispatch}}>
      <div className="App">
        <div className="create_box">
          <input
            type="text"
            id="input"
            onChange={({ target }) => {
              setValue({
                [target.id]: target.value,
                text: todoValue.text,
              });
            }}
          />
          <textarea
            id="text"
            onChange={({ target }) => {
              setValue({
                input: todoValue.input,
                [target.id]: target.value,
              });
            }}
          ></textarea>
          <button onClick={()=>dispatch({
            type:'add',
            title:todoValue.input,
            text:todoValue.text
            })}> add </button>
        </div>
        <div className="todo_list" >
          <TodoList todo={state} />
        </div>
      </div>
    </ContextApp.Provider>
  );
}

export default App;


TodoItem.js // вот здесь чекбокс
import React, { useContext } from 'react';
import { ContextApp } from './App';

const TodoItem = ({title,desc,checked,id}) => {
    const {dispatch} = useContext(ContextApp)
    return (
        <div className={!checked?"todo_item":"todo_item check"}>
            <h2>{title}</h2>
            <p className="desc">{desc} </p>
            <input type="checkBox" checked={checked} onChange={()=>{dispatch({
                type:'checked',
                id
            })}} />
            <button onClick={()=>{
                dispatch({
                    type:'del',
                    id
                })
            }}>del</button>
        </div>
    );
}
 
export default TodoItem;


import React from 'react'
import TodoItem from './TodoItem'

export default function TodoList({todo}) {
    return todo.map(item=> <TodoItem key={item.id} {...item} />)
};


На сайте уже есть похожий вопрос это я его задавал но правильного ответа не было
  • Вопрос задан
  • 387 просмотров
Решения вопроса 1
@paoluccio
switch (action.type) {
  // ...
  case 'checked':
    return state.map(item => {
      if (item.id === action.id) {
        return { ...item, checked: !item.checked };
      }
      return item;
    });
  // ...
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы