所以,我一直在研究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:无法读取未定义的属性“id”
现在,当我尝试在尝试切换待办事项时注销this.props.todos时,它返回undefined。这就是我得到错误的原因,因为由于某种原因,没有在click事件上传递this.props.todos。但是,我阅读了课程笔记,并且我有完全相同的代码。我在这做错了什么?我该如何解决?
答案 0 :(得分:1)
这是你所遵循的例子吗? 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>
);
答案 1 :(得分:1)
问题在于你的todos reducer中的“TOGGLE_TODO”案例。你有这个代码:
return state.map(t => {todo(t, action)})
括号是不必要的,并使箭头函数期望返回语句。由于没有return语句,返回值是未定义的,因此您将获得一个未定义值的数组。
将其更改为
return state.map(t => todo(t, action));