【问题标题】:TypeError: Cannot read property "map" of undefinedTypeError:无法读取未定义的属性“地图”
【发布时间】:2019-03-02 21:14:12
【问题描述】:

我正在关注 ReactJS AJAX and APIs tutorial。我在 Spring 中编写了一个简单的 API,然后在 http://localhost:8080 处编写了一个 React 组件来使用该 API。 API 目前返回一个包含以下两项的列表:

[
    {brand:"Asus", make:"AAA"},
    {brand:"Acer", make:"BBB"}
]

这是我的组件的样子:

import React from 'react';
import ReactDOM from 'react-dom';

import { environment } from '../environment/environment';

export class ComputerList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      error: null,
      isLoaded: false,
      items: [
        {brand: null, make: null}
      ]
    };
  }

  componentDidMount() {
    fetch("http://localhost:8080/computers")
    .then(res => res.json())
    .then(
      (result) => {
        // correctly displays the results
        console.log(result);
        this.setState({
          isLoaded: true,
          items: result.items
        });
      },
      (error) => {
        this.setState({
          isLoaded: true,
          error
        });
      }
    )
  }

  render() {
    const { error, isLoaded, items } = this.state;

    if(error) {
      return(<div>Error: {error.message}</div>);
    }
    else if(!isLoaded) {
      return(<div>Loading...</div>);
    }
    else if(items) {
      console.log(items);
      // error here: cannot read property "map" of undefined
      // because this.state.items is undefined somehow?
      return(
        <ul>
          {items.map(item => (
            <li key={item.make}>{item.brand} {item.make}</li>
          ))}
        </ul>
      );
    }
  }
}

在第 24 行,成功检索并记录了结果。

但是在第 54 行,当我尝试将每个结果映射到 &lt;li&gt; 项目时,TypeError 被抛出,因为 items 不知何故未定义?我通过在第 12 行初始化 items 并在第 48 行检查 items 来跟踪similar question 的答案,但无济于事。

我该如何解决这个问题?

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    只要这样做。避免渲染中的 if 循环,而是直接使用 && 运算符或三元运算符来管理 if 检查

      return(
        <ul>
          {!isLoaded && <div>Loading...</div>}
           {error && !isLoaded && <div>Error: {error.message}</div>)}
          {!isLoaded && items && items.map(item => (
            <li key={item.make}>{item.brand} {item.make}</li>
          ))}
        </ul>
      );
    

    此外,您在对象中的 make 键最初包含 null 值,因此您不能将其分配为键。相反,您可以做的是尝试从后端为数组中的对象生成唯一 id,或者使用类似下面的东西

     return(
        <ul>
          {items && items.map((item, index) => (
            <li key={"key"+index}>{item.brand} {item.make}</li>
          ))}
        </ul>
      );
    

    请原谅我的打字错误,因为我是用手机回答的

    【讨论】:

    • 感谢您的建议!我会记下额外的验证。关于 && 运算符,是否有理由在 if 语句上使用它?我发现if 语句更容易阅读(无论如何对我来说)。
    • 你应该保持你的渲染部分尽可能干净。由于您是 && 运算符三元运算符的新手,您会觉得 if else 很简单,但是当您开始使用这些运算符实现时,您会觉得这比 if else 更方便。假设如果其他检查组件,您需要做 10 次?你会在渲染部分检查所有这些看起来笨拙的代码吗?所以基本上这两个运算符在 React 中被大量用于管理 if else 并且它们很简单:)
    【解决方案2】:

    感谢@DacreDenny 的建议:)

    第 27 行:items: result.items。此行期望响应包含名为“items”的对象。

    但我的 API 只返回一个对象数组。所以我把行改为

    第 27 行至:items: result。这会将整个数组保存到state.items。然后可以正确映射和渲染。

    【讨论】:

      【解决方案3】:

      这可能是因为 items 的类型不是数组,这就是为什么不会定义 map() 方法的原因。

      对于更强大的render() 方法,您可以将else if(items) { 替换为else if(Array.isArray(items)) {,这样可以防止您看到的错误消息:

      render() {
          const { error, isLoaded, items } = this.state;
      
          if(error) {
            return(<div>Error: {error.message}</div>);
          }
          else if(!isLoaded) {
            return(<div>Loading...</div>);
          }
          else if(Array.isArray(items)) { // <-- update here
            console.log(items);
            // error here: cannot read property "map" of undefined
            // because this.state.items is undefined somehow?
            return(
              <ul>
                {items.map(item => (
                  <li key={item.make}>{item.brand} {item.make}</li>
                ))}
              </ul>
            );
          }
        }
      

      希望有帮助!

      【讨论】:

      • 当我这样做时,我得到了错误Nothing was returned from render。如果没有返回任何内容,则意味着不满足任何条件 - 即 items 可能不是 Array 类型。我得调查一下。
      • @Jason 看起来items 的类型不是数组。你能用console.log(typeof result.items)重播console.log(result);并告诉我记录了什么吗?
      • 多亏了您的建议,才能够弄清楚。在第 27 行,我将 items:result.items 更改为 items:result。前者需要一个名为items 的对象,而后者只是保存响应(这是一个对象数组)。更改后,信息正确呈现。
      猜你喜欢
      • 2022-01-14
      • 1970-01-01
      • 1970-01-01
      • 2021-11-17
      • 2022-01-12
      • 2021-02-25
      • 2018-02-08
      • 2019-10-05
      相关资源
      最近更新 更多