Redux动作没有触发onclick

时间:2017-10-07 12:35:35

标签: reactjs redux react-redux

做一个redux todo来学习并在切换待办事项上遇到麻烦。

当我触发onclick时,我在控制台中收到错误。

"道具类型失败:道具itemsItemsList标记为必需,但其值为undefined。"

"无法读取属性'长度'未定义" on items.length

我安慰记录了这个动作,它似乎正在恢复状态。不确定我做错了什么。代码如下。

动作

export const addItem = content => {
  return { type: ADD_ITEM, content };
};

export const toggleTodo = (id) => {
  return {
    type: TOGGLE_TODO,
    id,
  };
};

我的初始状态是:

       import { ADD_ITEM, TOGGLE_TODO } from './constants';

let nextId = 4;

export const initialState = {
  items: [
    { id: 1, content: 'Call mum', completed: false},
    { id: 2, content: 'Buy cat food', completed: true },
    { id: 3, content: 'Water the plants', completed: false },
  ],
};

const reducer = (state = initialState, action) => {
  console.log("action", action.type);
  switch (action.type) {
    case ADD_ITEM:
      const newItem = {
        id: nextId++,
        content: action.content,
        completed: false
      };

      return {
        ...state,
        items: [...state.items, newItem],
      };
    case TOGGLE_TODO:
      return state.items.map(todo => {
            console.log("state", state);
            console.log("state.items", state.items);
            console.log("todo",todo);
            if (todo.id !== action.id) {
              return state;
            }
            return {
                ...state,
                completed: !todo.completed,
          };
      });
    default:
      return state;
  }
};

export default reducer;

我的列表组件是

    import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Todo from "../ItemTodo/index"
import { toggleTodo } from "../../logic/actions";
import './styles.css';

export const ItemsList = ({ items, onTodoClick }) => {
  return (
    <div>
      <ul className={'itemsList-ul'}>
        {items.length < 1 && <p id={'items-missing'}>Add some tasks above.</p>}
        {items.map(item =>
          <Todo
            key={item.id}
            {...item}
            onClick={() => onTodoClick(item.id)}
          />
        )}
      </ul>
    </div>
  );
};

ItemsList.propTypes = {
  items: PropTypes.array.isRequired,
  onTodoClick: PropTypes.func.isRequired,
};

const mapStateToProps = state => {
  return { items: state.todos.items };
};

const mapDispatchToProps = dispatch => ({
  onTodoClick: id => dispatch(toggleTodo(id))
});

export default connect(mapStateToProps, mapDispatchToProps)(ItemsList);

我的待办事项组件是

import React from 'react';
import PropTypes from 'prop-types';

const Todo = ({onClick, completed, content }) => (
        <li
        onClick={onClick}
        style={{
            textDecoration: completed ? 'line-through' : 'none',
        }}
        >
        {content}
        </li>
);

Todo.propTypes = {
    onClick: PropTypes.func.isRequired,
    completed: PropTypes.bool.isRequired,
    content: PropTypes.string.isRequired,
};

export default Todo;

创建商店

import React, { Component } from 'react';
import { Provider } from 'react-redux';
import configureStore from './redux/store';
import Header from './components/Header';
import ItemCreator from './components/ItemCreator';
import ItemsList from './components/ItemsList';
import './app.css';

const store = configureStore();

class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <div className="app">
          <Header />
          <div>
            <ItemCreator />
            <ItemsList />
          </div>
        </div>
      </Provider>
    );
  }
}

export default App;


import { createStore, applyMiddleware, compose } from 'redux';
import createReducer from './reducers';

const composeEnhancers =
  (process.env.NODE_ENV !== 'production' &&
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) ||
  compose;

const configureStore = (initialState = {}) => {
  return createStore(
    createReducer(),
    initialState,
    composeEnhancers(applyMiddleware())
  );
};

export default configureStore;

import { combineReducers } from 'redux';
import reducer from '../logic/reducer';

export default function createReducer() {
  return combineReducers({
    todos: reducer,
  });
}

1 个答案:

答案 0 :(得分:0)

我还没有测试过,但我认为这部分不正确TOGGLE_TODO

  return state.items.map(todo => {
        console.log("state", state);
        console.log("state.items", state.items);
        console.log("todo",todo);
        if (todo.id !== action.id) {
          return state;
        }
        return {
            ...state,
            completed: !todo.completed,
      };
  });

它应该是:

return {
    ...state,
    items: state.items.map((todo) => {
        if (todo.id === action.id) {
            return { ...todo, completed: !todo.completed };
        }
        return todo;
    })
};