Javascript Egghead Redux教程:第19课

Javascript Egghead Redux教程:第19课,javascript,redux,Javascript,Redux,我得到这个错误,我不知道为什么。我想我错过了一步。这节课我复习了好几遍,但都不知道我做错了什么 "error" "TypeError: Cannot read property 'map' of undefined at TodoApp.render (xuwuwoqaso.js:157:23) 代码如下。我认为它指的是TodoApp下的.map函数,带有visibleTodos.map(todo=>…) 据我所知,store.getState()正在传入,然后映射到visibleTo

我得到这个错误,我不知道为什么。我想我错过了一步。这节课我复习了好几遍,但都不知道我做错了什么

"error"
"TypeError: Cannot read property 'map' of undefined
    at TodoApp.render (xuwuwoqaso.js:157:23)
代码如下。我认为它指的是
TodoApp
下的.map函数,带有
visibleTodos.map(todo=>…)

据我所知,
store.getState()
正在传入,然后映射到
visibleTodos
并创建错误。是这样吗

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 visbilityFilter = (
  state = 'SHOW_ALL',
  action
) => {
  switch (action.type) {
    case 'SET_VISIBILITY_FILTER':
      return action.filter;
    default:
      return state;
  }
}

const { combineReducers } = Redux
const todoApp = combineReducers({
  todos,
  visbilityFilter
});

const { createStore } = Redux;
const store = createStore(todoApp);
const { Component } = React;

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

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 Component {
  render() {
    const visibleTodos = getVisibleTodos(
      this.props.todos,
      this.props.visibilityFilter
    );
    return (
      <div>
        <input ref ={node => {
          this.input = node;
        }} />

        <button onClick = {() => {
          store.dispatch({
            type: 'ADD_TODO', 
            text: this.input.value, 
            id: nextTodoId++
          });
          this.input.value = ''
        }}>
          Add Todo
        </button>
        <ul>
          {visibleTodos.map(todo =>
            <li key={todo.id} 
                onClick={() => {
                  store.dispatch({
                    type:'TOGGLE_TODO',
                    id:todo.id
                  });
                }}
                style = {{
                  textDecoration: 
                    todo.completed ?
                      'line-through' :
                        'none'
                }}>
              {todo.text}
            </li>
          )}
        </ul>
        <p>
          Show:
          {' '}
          <FilterLink filter='SHOW_ALL'>All</FilterLink>
          {' '}
          <FilterLink filter='SHOW_ACTIVE'>Active</FilterLink>
          {' '}
          <FilterLink filter='SHOW_COMPLETED'>Completed</FilterLink>
          {' '}
        </p>
      </div>

    )
  }
}

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

store.subscribe(render);

render()
const todo=(状态、操作)=>{
开关(动作类型){
案例“ADD_TODO”:
返回{
id:action.id,
text:action.text,
已完成:false
}
案例“TOGGLE_TODO”:
if(state.id!==action.id){
返回状态;
}
返回{
……国家,
已完成:!state.completed
};
违约:
返回状态
}
}
常量todos=(状态=[],操作)=>{
开关(动作类型){
案例“ADD_TODO”:
返回[
……国家,
todo(未定义,动作)
];
案例“TOGGLE_TODO”:
返回state.map(t=>todo(t,action))
违约:
返回状态;
}
};
常量粘度过滤器=(
状态='SHOW_ALL',
行动
) => {
开关(动作类型){
案例“设置可见性过滤器”:
返回操作.filter;
违约:
返回状态;
}
}
const{combineReducers}=Redux
const todoApp=组合减速机({
待办事项,
粘度过滤器
});
const{createStore}=Redux;
const store=createStore(todoApp);
常数{Component}=React;
常量过滤器链接=({
过滤器,
儿童
}) => {
返回(
);
};
常量getVisibleTodos=(
待办事项,
滤波器
) => {
开关(过滤器){
“全部展示”案例:
返回待办事项;
案例“SHOW_COMPLETED”:
返回todos.filter(
t=>t已完成
);
案例“SHOW_ACTIVE”:
返回todos.filter(
t=>!t已完成
);
}
}
设nextTodoId=0
类TodoApp扩展组件{
render(){
const visibleTodos=getVisibleTodos(
这个.props.todos,
this.props.visibilityFilter
);
返回(
{
this.input=节点;
}} />
{
仓库调度({
键入:“ADD_TODO”,
text:this.input.value,
id:nextTodoId++
});
this.input.value=“”
}}>
添加待办事项
    {visibleTodos.map(todo=>
  • { 仓库调度({ 类型:'TOGGLE_TODO', id:todo.id }); }} 样式={{ 文本装饰: 完成了吗? “线路通过”: “没有” }}> {todo.text}
  • )}
展示: {' '} 全部的 {' '} 活跃的 {' '} 完整的 {' '}

) } } 常量渲染=()=>{ ReactDOM.render( , document.getElementById('root')) ) }; 存储。订阅(呈现); render()
您的
类TodoApp扩展组件{
@connect
连接到您的redux存储,这将为您的组件存储数据提供道具。然后调用

const visibleTodos = getVisibleTodos(
  this.props.todos,
  this.props.visibilityFilter
);
但是,由于您尚未将组件连接到存储,因此道具将为空,并且您正在使用空参数调用
getVisibleTodos


你需要下载你的
TodoApp
组件,教程视频中已经详细介绍了该组件。你可能是无意中跳过了它。

这是
VisibilityFilter
woops!的拼写错误。

存储。订阅(渲染)
连接它?哇,我错过了那一行!