【问题标题】:cannot read property 'id' of undefined in ReactJS无法读取 ReactJS 中未定义的属性“id”
【发布时间】:2020-04-23 01:43:46
【问题描述】:

我目前是基于 react-redux 的 React SPA 应用程序。在 reducer.js 中,我有两个主要状态,即 mylist 和 Recommendations。我附上了两张实际应用的图片。有两页。第一个是主页,其中有三个电影的初始推荐。在每部电影下面都有一个添加按钮,一旦您单击该按钮并选择了期望的电影,该按钮将被删除并添加到第二页,即 mylist 页面。

在我的列表页面上,会有三部初始电影。每部电影下面都有一个删除按钮,一旦我点击了删除按钮,期望是选定的电影被删除并被添加回主页。

现在,我已经实现了添加按钮,一旦我点击添加按钮,所选电影将被删除并添加到我的列表页面。

单击删除后,问题就出在 mylist 页面中。选定的电影被删除,但没有添加到主页。

Home.js

class Home extends Component {
  handleClick = id => {
    this.props.addToList(id);
    this.props.removeFromRecom(id);
  };
  render() {
    let addedRecom1 = this.props.addedRecom.map(item => {
      return (
        <div key={item.id} style={{ float: "left", marginLeft: "20px" }}>
          <Image webP={item.img}></Image>
          <p style={{ marginLeft: "44px" }}>{item.title}</p>
          <button
            to="/"
            onClick={() => this.handleClick(item.id)}
            style={{
              marginLeft: "53px",
              paddingLeft: "10px",
              paddingRight: "10px",
              paddingTop: "0px",
              marginTop: "0px",
              marginBottom: "20px"
            }}
          >
            add
          </button>
        </div>
      );
    });
    return (
      <div>
        <div>
          <NavLink to="/myList" style={{ textDecoration: "none" }}>
            <a
              style={{
                marginLeft: "378px",
                fontFamily: "Arial Black",
                color: "black",
                border: "solid 1px",
                backgroundColor: "orange",
                paddingLeft: "35px",
                paddingRight: "20px"
              }}
            >
              <i
                class="fa fa-plus"
                style={{ paddingRight: "10px", paddingLeft: "5px" }}
              ></i>
              My list
            </a>
          </NavLink>
          <p style={{ marginTop: "20px", marginLeft: "20px" }}>
            Recommendations
          </p>
        </div>
        <div>
          {this.props.recommendations.map(item => {
            return (
              <div key={item.id} style={{ float: "left", marginLeft: "20px" }}>
                <Image webP={item.img}></Image>
                <p style={{ marginLeft: "44px" }}>{item.title}</p>
                <button
                  to="/"
                  onClick={() => this.handleClick(item.id)}
                  style={{
                    marginLeft: "53px",
                    paddingLeft: "10px",
                    paddingRight: "10px",
                    paddingTop: "0px",
                    marginTop: "0px",
                    marginBottom: "20px"
                  }}
                >
                  add
                </button>
              </div>
            );
          })}
        </div>
        {addedRecom1}
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    addedRecom: state.addedRecom,
    recommendations: state.recommendations
  };
};

const mapDispatchToProps = dispatch => {
  return {
    addToList: id => {
      dispatch(addToList(id));
    },
    removeFromRecom: id => {
      dispatch(removeFromRecom(id));
    }
  };
};

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

MyList.js

class MyList extends Component {
  handleRemoveMovie = id => {
    this.props.removeFromList(id);
    this.props.addToRecom(id);
  };
  render() {
    let addedMovies = this.props.addedMovies.map(item => {
      return (
        <div key={item.id} style={{ float: "left", marginLeft: "20px" }}>
          <Image webP={item.img}></Image>
          <p style={{ marginLeft: "44px" }}>{item.title}</p>
          <button
            to="myList"
            onClick={() => {
              this.handleRemoveMovie(item.id);
            }}
            style={{
              marginLeft: "53px",
              paddingLeft: "10px",
              paddingRight: "10px",
              paddingTop: "0px",
              marginTop: "0px",
              marginBottom: "20px"
            }}
          >
            remove
          </button>
        </div>
      );
    });
    return (
      <div>
        <div>
          <NavLink to="/" style={{ textDecoration: "none" }}>
            <a
              style={{
                marginLeft: "317px",
                fontFamily: "Arial Black",
                color: "black",
                border: "solid 1px",
                backgroundColor: "orange",
                paddingLeft: "28px",
                paddingRight: "20px"
              }}
            >
              <i
                class="fa fa-hand-o-left"
                style={{ paddingRight: "10px", paddingLeft: "5px" }}
              ></i>
              back to Home
            </a>
          </NavLink>
          <p style={{ marginTop: "20px", marginLeft: "20px" }}>My Lists</p>
        </div>
        <div>
          {this.props.mylist.map(item => {
            return (
              <div key={item.id} style={{ float: "left", marginLeft: "20px" }}>
                <Image webP={item.img}></Image>
                <p style={{ marginLeft: "44px" }}>{item.title}</p>
                <button
                  to="myList"
                  onClick={() => {
                    this.handleRemoveMovie(item.id);
                  }}
                  style={{
                    marginLeft: "53px",
                    paddingLeft: "10px",
                    paddingRight: "10px",
                    paddingTop: "0px",
                    marginTop: "0px",
                    marginBottom: "20px"
                  }}
                >
                  remove
                </button>
              </div>
            );
          })}
        </div>
        {addedMovies}
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    addedMovies: state.addedMovies,
    mylist: state.mylist
  };
};

const mapDispatchToProps = dispatch => {
  return {
    removeFromList: id => {
      dispatch(removeFromList(id));
    },
    addToRecom: id => {
      dispatch(addToRecom(id));
    }
  };
};

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

reducer.js

const initialState = {
  mylist: [
    {
      title: "Futurama",
      id: 1,
      img: "http://cdn1.nflximg.net/webp/7621/3787621.webp"
    },
    {
      title: "The Interview",
      id: 2,
      img: "http://cdn1.nflximg.net/webp/1381/11971381.webp"
    },
    {
      title: "Gilmore Girls",
      id: 3,
      img: "http://cdn1.nflximg.net/webp/7451/11317451.webp"
    }
  ],
  recommendations: [
    {
      title: "Family Guy",
      id: 4,
      img: "http://cdn5.nflximg.net/webp/5815/2515815.webp"
    },
    {
      title: "The Croods",
      id: 5,
      img: "http://cdn3.nflximg.net/webp/2353/3862353.webp"
    },
    {
      title: "Friends",
      id: 6,
      img: "http://cdn0.nflximg.net/webp/3200/9163200.webp"
    }
  ],
  addedMovies: [],
  addedRecom: []
};

const reducer = (state = initialState, action) => {
  if (action.type === REMOVE_FROM_RECOM) {
    let Recom = state.recommendations.filter(item => item.id !== action.id);
    return {
      ...state,
      recommendations: Recom
    };
  }

  if (action.type === ADD_TO_LIST) {
    let addedMovie = state.recommendations.find(item => item.id === action.id);
    let existed_movie = state.mylist;
    if (existed_movie) {
      return {
        ...state,
        addedMovies: [...state.addedMovies, addedMovie]
      };
    }
  }

  if (action.type === ADD_TO_RECOM) {
    let add_recom = state.mylist.find(item => item.id === action.id);
    let current_recom = state.recommendations;
    if (current_recom) {
      return {
        ...state,
        addedRecom: [...state.addedRecom, add_recom]
      };
    }
  }

  if (action.type === REMOVE_FROM_LIST) {
    let removedMovie = state.mylist.find(item => item.id === action.id);
    let newMovie = state.addedMovies.filter(item => item.id !== action.id);
    return {
      ...state,
      addedMovies: newMovie
    };
  } else {
    return state;
  }
};[![enter image description here][1]][1]

export default reducer;


TypeError: Cannot read property 'id' of undefined
(anonymous function)
src/Home.js:17

  14 | render() {
  15 |   let addedRecom1 = this.props.addedRecom.map(item => {
  16 |     return (
> 17 |       <div key={item.id} style={{ float: "left", marginLeft: "20px" }}>
     | ^  18 |         <Image webP={item.img}></Image>
  19 |         <p style={{ marginLeft: "44px" }}>{item.title}</p>
  20 |         <button

[![在此处输入图片描述][1]][1]

【问题讨论】:

  • 让我们更新您的问题。让我们对其进行编辑以清楚地说明问题是什么,您有什么结果以及您期望什么结果。只包括代码的相关部分。这样可以更轻松地了解您的问题并提出解决方案。
  • 我怀疑问题出在let add_recom = state.mylist.find(item =&gt; item.id === action.id); 如果add_recom 未定义,它可能会抛出该错误。
  • 我又编辑了,很抱歉造成混乱,希望这次很清楚@Ibu
  • 感谢@Neil Chowdhury 的评论 state.mylist 有问题吗?
  • 使用 redux devtools 并观察商店,或在出现错误之前运行 console.log(state.mylist) 以查看问题所在

标签: javascript reactjs typescript redux reducers


【解决方案1】:

通常你应该只有两个列表,一个用于recommendations,一个用于myList,以及两个处理来自myList的项目的删除和添加的reducer:

const initialState = {
    myList: [
        {
            title: 'Futurama',
            id: 1,
            img: 'http://cdn1.nflximg.net/webp/7621/3787621.webp'
        },
        {
            title: 'The Interview',
            id: 2,
            img: 'http://cdn1.nflximg.net/webp/1381/11971381.webp'
        },
        {
            title: 'Gilmore Girls',
            id: 3,
            img: 'http://cdn1.nflximg.net/webp/7451/11317451.webp'
        }
    ],
    recommendations: [
        {
            title: 'Family Guy',
            id: 4,
            img: 'http://cdn5.nflximg.net/webp/5815/2515815.webp'
        },
        {
            title: 'The Croods',
            id: 5,
            img: 'http://cdn3.nflximg.net/webp/2353/3862353.webp'
        },
        {
            title: 'Friends',
            id: 6,
            img: 'http://cdn0.nflximg.net/webp/3200/9163200.webp'
        }
    ]
};

每个reducer负责在删除/添加电影时更新recommendationsmyList

const reducer = (state = initialState, action) => {
    if (action.type === 'ADD_TO_LIST') {
        let addToMyList = state.recommendations.find(item => item.id === action.id);
        return {
            ...state,
            myList: [ ...state.myList, addToMyList ],
            recommendations: state.recommendations.filter(item => item.id !== action.id)
        };
    }

    if (action.type === 'REMOVE_FROM_LIST') {
        let removedItem = state.myList.find(item => item.id === action.id);
        return {
            ...state,
            myList: state.myList.filter(item => item.id !== action.id),
            recommendations: [ ...state.recommendations, removedItem ]
        };
    } else {
        return state;
    }
};

export default reducer;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-08
    • 2018-12-16
    • 1970-01-01
    • 1970-01-01
    • 2021-12-06
    • 2021-12-06
    • 2022-07-22
    • 2019-11-18
    相关资源
    最近更新 更多