javascript - 为什么 toggle todo 在 Redux 中不起作用?

标签 javascript reactjs react-redux

因此,我一直在研究 Dan Abramov 的 Redux 教程,您可以在其中构建一个简单的待办事项应用程序。这是主要渲染功能的代码,

const todo = (state, action) => {
    switch(action.type){
        case 'ADD_TODO':
            return {
                id: action.id, 
                text: action.text, 
                completed: false
            }
        case 'TOGGLE_TODO': 
            if(state.id !== action.id){
                return state
            }
            return {...state,
                completed: !state.completed
            }

        default:
            return state
    }
}

const todos = (state = [], action) => {
    switch(action.type){
        case "ADD_TODO": 
            return [
                ...state, 
                todo(undefined, action)
            ]
        case "TOGGLE_TODO": 
            return state.map(t => {
                todo(t, action)
            })
        default: 
            return state;
    }
}

const visibilityFilter = (state = 'SHOW_ALL', action) => {
    switch(action.type){
        case 'SET_VISIBILITY_FILTER': 
            return action.filter
        default:
            return state
    }
}


const todoApp = combineReducers({
    visibilityFilter, 
    todos
});

const store = createStore(todoApp);

const FilterLink = ({
    filter, 
    currentFilter,
    children
}) => {
    if(filter === currentFilter){
        return <span>{children}</span>
    }
    return (
        <a href='#' onClick={e => {
            e.preventDefault();
            store.dispatch({
                type: 'SET_VISIBILITY_FILTER', 
                filter
            })
        }}>
            {children}
        </a>
    )
}

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

const TodoList = ({
    todos, 
    onTodoClick
}) => (
    <ul>
        {todos.map(todo => 
            <Todo key={todo.id} {...todo}
            onClick={() => onTodoClick(todo.id)} />
        )}
    </ul>
);

const getVisibleTodos = (todos, filter) => {
    switch(filter){
        case 'SHOW_ALL':
            return todos;
        case 'SHOW_COMPLETED':
            return todos.filter(
                t => t.completed
            )
        case 'SHOW_ACTIVE':
            return todos.filter(
                t => !t.completed
            )
    }
}

let nextTodoId = 0;
class TodoApp extends React.Component {
    render() {
        const {
            todos, 
            visibilityFilter
        } = this.props
        const visibleTodos = getVisibleTodos(todos, visibilityFilter);
        return (
            <div>
                <input ref={text => {
                    this.input = text;
                }} />
                <button onClick={() => {
                    store.dispatch({
                        type:"ADD_TODO", 
                        text: this.input.value, 
                        id: nextTodoId++
                    });
                    this.input.value = '';
                }}>Add a todo
                </button>
                <TodoList todos={visibleTodos} onTodoClick={id => store.dispatch({
                    type: 'TOGGLE_TODO', 
                    id
                })} />
                <p>
                    Show: 
                    {' '}
                    <FilterLink filter='SHOW_ALL' currentFilter={visibilityFilter}>
                        All
                    </FilterLink>
                    {' '}
                    <FilterLink filter='SHOW_COMPLETED' currentFilter={visibilityFilter}>
                        Completed
                    </FilterLink>
                    {' '}
                    <FilterLink filter='SHOW_ACTIVE' currentFilter={visibilityFilter}>
                        Active
                    </FilterLink>
                </p>
            </div>
        )
    }
}



const render = () => {
    console.log(store.getState());
    ReactDOM.render(<TodoApp {...store.getState()}/>, document.getElementById('root'));
}

store.subscribe(render);
render();

当我尝试切换待办事项时,出现以下错误,

index.js:170 Uncaught TypeError: Cannot read property 'id' of undefined

现在,当我尝试在尝试切换待办事项时注销 this.props.todos 时,它返回未定义。这就是我收到错误的原因,因为出于某种原因 this.props.todos 没有在点击事件上传递。但是,我浏览了类(class)笔记并且我有完全相同的代码。我在这里做错了什么?我该如何解决?

最佳答案

这是您要效仿的例子吗? https://github.com/reactjs/redux/tree/master/examples/todos

不确定是否与此有关,但在您的 Todo 中,您可能想要删除 onClick 周围的 ()

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

关于javascript - 为什么 toggle todo 在 Redux 中不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40500586/

相关文章:

ReactJS:在父组件的子组件中禁用鼠标事件

javascript - 执行代码之前等待 while 循环结束

javascript - 将 img src 插入输入 onClick

javascript - 从框架中的其他 iframe 隐藏 iframe 或 div

node.js - 带有 Nest js 后端 api 的 Azure Active Directory Spa 用户流程

javascript - 我没有在构造函数中绑定(bind)函数的 "this",但为什么 "this"不是未定义的?

javascript - 表格溢出时奇怪的 HTML 表格行高

javascript - 无法更新 React Native 中的状态?

javascript - redux-react 简单的 Hello World

javascript - 如何在 react componentDidUpdate 方法中触发 redux 操作?