Не удается добавить todo в список задач с помощью react и redux. Что я делаю не так?

#javascript #reactjs #redux #react-redux

#javascript #reactjs #redux #react-redux

Вопрос:

    render() {
    const listItems = this.props.todos.map((todo) =>
      <ListItem key={todo.id} id={todo.id} content={todo.content} onEdit={this.onEditItem}/>
    )
    return <>
      <ul className="todo-list">
        {listItems}
      </ul>
      {/* <AddItem/> */}
      <div className="add-item">
        <input type="text" onChange={this.onChangeValue}/>
        <button type="submit" onClick={this.onAddItem}>Add Item</button>
      </div>
    </>
  }
 
 onAddItem = () => {
    this.props.submitNewTodo({ id: this.props.todos.length   1, content: this.state.value})
    };
 

Когда я console.log this.props.todos.length , он возвращает значение 2 и this.state.value возвращает значение, введенное во ввод. Но кнопка «Добавить элемент» не работает.

Я сопоставил submitNewTodo с dispatch addTodo(newTodo) следующим образом

 const mapDispatchToProps = (dispatch) => {
  return {
    submitNewTodo: function(newTodo) {
      dispatch(addTodo(newTodo));
    }
  }
}
 

Полный код находится в этом codepen .

https://codepen.io/blenderous/pen/MWjdyoN?editors=0011

Ответ №1:

Ваш addTodo создатель действия ошибается:

 const addTodo = (todo) => {
  type: 'ADD_TODO',
  todo
};
 

это метод, который обрабатывает

   type: 'ADD_TODO',
  todo
 

как тело метода. ( type используется в качестве метки разрыва для строки 'ADD_TODO' , за которой следует todo )

Если вы хотите вернуть действие, эти два обозначения верны:

 const addTodo = (todo) => {
  return {
    type: 'ADD_TODO',
    todo
  }
};
// note the parantheses!
const addTodo = (todo) => ({
  type: 'ADD_TODO',
  todo
});
 

Комментарии:

1. Кроме того, общее замечание: это очень старый стиль redux, если вы изучаете redux прямо сейчас, возможно, вы следуете очень старому учебному пособию, которое научит вас стилю redux, который в конечном итоге будет намного длиннее, чем требуется на самом деле. Пожалуйста, следуйте официальным руководствам: redux.js.org/tutorials/index

Ответ №2:

Первое, что я замечаю в вашем коде, это то, что ваш редуктор не следует шаблону, используемому Redux.

 const todoReducer = ( state = [{ id: 1, content: "Call Client" },
       { id: 2, content: "Write Log" }], action ) => {
  if (action.type == ADD_TODO) {
    return state.concat(action.todo);
  }
  else {
    return state;
  }
}
 

Первое правило, которое он нарушает, заключается в том, что это должен быть переключатель, а не оператор if .

 switch (action.type) {
  case 'ADD_TODO':
    // create new todos with the added todo
    const newTodos = [
      ...state.todos,
      action.payload.todo,
    ]
    
    // new state object
    return {
      ...state,
      todos: newTodos,
    }

  default:
    return {
      ...state,
    }

}
 

Второе правило заключается в том, что вы хотите всегда иметь свойство полезной нагрузки, чтобы следовать правильным шаблонам потока. Эта полезная нагрузка будет содержать все ваши данные.

 const addTodo = (todo) => {
  type: 'ADD_TODO',
  payload: {
    todo,
  }
};
 

Комментарии:

1. Я уже использовал компонент connect из react-redux вот так const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);

2. вы можете просмотреть весь код моего приложения здесь: codepen.io/blenderous/pen/MWjdyoN?editors=0011

3. Привет, случайный сопровождающий redux. Просто чтобы прояснить это: switch может быть соглашением (и только в старых стилях redux, современный redux в целом сильно отличается), но определенно не является фиксированным правилом. То же самое касается свойства полезной нагрузки. Это не необходимость, только соглашение.

4. Справедливо, я полагаю, что это не остановит компиляцию кода, но определенно значительно упростит отладку.