开发者问题收集

无法访问 React 中对象或数组中的特定键

2017-05-28
4631

更新 我可以在 render() 函数的 return 语句中正常访问所有内容。例如 user.exercises[0].exercise.name 输出“squats”。这就是为什么更令人困惑的是为什么我无法在 return 语句之前访问它以创建将值映射到表的函数。 更新

我似乎在访问 React 中的特定键时遇到问题。我尝试读取的对象是从 mongodb 的后端 API 请求的,并以 JSON 形式输出。我已经尝试过通过 lodash 将对象映射到数组后访问它,但问题是一样的。我可能只是错误地读取了对象并指定了错误的键,但我看不到它。我对 console.logging 整个 JSON 或顶部键(例如“name”或“age”)没有任何问题,方法是编写 {user.name},但任何更深层次的内容都会崩溃。这是 JSON:

{
    "_id": "592ab4523a4d39085fe4c1d9",
    "nickname": "mmsmsy",
    "name": "Mateusz",
    "gender": "male",
    "age": 26,
    "exercises": [
      {
        "exercise": {
          "name": "squats",
          "records": []
        }
      },
      {
        "exercise": {
          "name": "legpresses",
          "records": []
        }
      },
      {
        "exercise": {
          "name": "deadlifts",
          "records": []
        }
      },
      {
        "exercise": {
          "name": "benchpresses",
          "records": []
        }
      },
      {
        "exercise": {
          "name": "pullups",
          "records": []
        }
      },
      {
        "exercise": {
          "name": "shoulderpresses",
          "records": []
        }
      },
      {
        "exercise": {
          "name": "curls",
          "records": []
        }
      }
    ]
  }

以及 React 代码:

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
import _ from 'lodash';

class UserDetails extends Component{
  constructor(props) {
    super(props)
    this.state = {
      user: null,
      loading: false
    }
  }
  componentDidMount() {
    this.setState({
      loading: true
    });
    axios.get(`http://192.168.0.248:3001/api/v1/users/${this.props.match.params.id}`)
      .then(res => res.data)
      .then(user => {
        this.setState({
          user: user,
          loading: false
        });
      });
  }
  render() {
    const {loading, user} = this.state;
    let userInfo = _.map(user, (value, prop) => {
        return { "prop": prop, "value": value };
      });
    console.log(user, userInfo);
    if (loading || !user) {
      return (
        <p className="user-loading">Loading ...</p>
      );
    }
    return (
      <div id="user-details">
        <div className="nav">
          <Link className="nav-back-to-list" to="/">Back to the list</Link>
        </div>
        <div id="user-details-icon">
          <img src={`/images/user_${user.gender}.png`} alt={`generic user ${user.gender} icon`} />
        </div>
        <table>
          <tbody><tr><td>Nickname</td><td>{user.nickname}</td></tr></tbody>
          <tbody><tr><td>Name</td><td>{user.name}</td></tr></tbody>
          <tbody><tr><td>Gender</td><td>{user.gender}</td></tr></tbody>
          <tbody><tr><td>Age</td><td>{user.age}</td></tr></tbody>
        </table>
        <h1>Records</h1>
      </div>
    )
  }
}

export default UserDetails;

这是我使用 console.log(user); 获得的结果,没有错误

Object {_id: "592ab4523a4d39085fe4c1d9", nickname: "mmsmsy", name: "Mateusz", gender: "male", age: 26…}age: 26exercises: Array(7)0: Objectexercise: Objectname: "squats"records: Array(0)length: 0__proto__: Array(0)__proto__: Objectconstructor: function Object()hasOwnProperty: function hasOwnProperty()isPrototypeOf: function isPrototypeOf()propertyIsEnumerable: function propertyIsEnumerable()toLocaleString: function toLocaleString()toString: function toString()valueOf: function valueOf()__defineGetter__: function __defineGetter__()__defineSetter__: function __defineSetter__()__lookupGetter__: function __lookupGetter__()__lookupSetter__: function __lookupSetter__()get __proto__: function __proto__()set __proto__: function __proto__()__proto__: Object1: Objectexercise: Object__proto__: Object2: Object3: Object4: Object5: Object6: Objectlength: 7__proto__: Array(0)gender: "male"name: "Mateusz"nickname: "mmsmsy"_id: "592ab4523a4d39085fe4c1d9"__proto__: Object

这是使用 lodash 将其转换为数组 console.log(userInfo);

(6) [Object, Object, Object, Object, Object, Object]

现在,示例和如果我尝试访问 f.e 时得到的错误: console.log(user.exercises[0].exercise.name);

Uncaught TypeError: Cannot read property 'exercises' of null
    at UserDetails.render (UserDetails.js:33)
    at ReactCompositeComponent.js:796
    at measureLifeCyclePerf (ReactCompositeComponent.js:75)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (ReactCompositeComponent.js:795)
    at ReactCompositeComponentWrapper._renderValidatedComponent (ReactCompositeComponent.js:822)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:362)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactDOMComponent.mountChildren (ReactMultiChild.js:238)
    at ReactDOMComponent._createInitialChildren (ReactDOMComponent.js:697)
    at ReactDOMComponent.mountComponent (ReactDOMComponent.js:516)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at mountComponentIntoNode (ReactMount.js:104)
    at ReactReconcileTransaction.perform (Transaction.js:140)
    at batchedMountComponentIntoNode (ReactMount.js:126)
    at ReactDefaultBatchingStrategyTransaction.perform (Transaction.js:140)
    at Object.batchedUpdates (ReactDefaultBatchingStrategy.js:62)
    at Object.batchedUpdates (ReactUpdates.js:97)
    at Object._renderNewRootComponent (ReactMount.js:320)
    at Object._renderSubtreeIntoContainer (ReactMount.js:401)
    at Object.render (ReactMount.js:422)
    at Object.<anonymous> (index.js:10)
    at __webpack_require__ (bootstrap 9a6d4f1…:657)
    at fn (bootstrap 9a6d4f1…:85)
    at Object.<anonymous> (fetch.js:461)
    at __webpack_require__ (bootstrap 9a6d4f1…:657)
    at validateFormat (bootstrap 9a6d4f1…:706)
    at bundle.js:710
render @ UserDetails.js:33
(anonymous) @ ReactCompositeComponent.js:796
measureLifeCyclePerf @ ReactCompositeComponent.js:75
_renderValidatedComponentWithoutOwnerOrContext @ ReactCompositeComponent.js:795
_renderValidatedComponent @ ReactCompositeComponent.js:822
performInitialMount @ ReactCompositeComponent.js:362
mountComponent @ ReactCompositeComponent.js:258
mountComponent @ ReactReconciler.js:46
performInitialMount @ ReactCompositeComponent.js:371
mountComponent @ ReactCompositeComponent.js:258
mountComponent @ ReactReconciler.js:46
mountChildren @ ReactMultiChild.js:238
_createInitialChildren @ ReactDOMComponent.js:697
mountComponent @ ReactDOMComponent.js:516
mountComponent @ ReactReconciler.js:46
performInitialMount @ ReactCompositeComponent.js:371
mountComponent @ ReactCompositeComponent.js:258
mountComponent @ ReactReconciler.js:46
performInitialMount @ ReactCompositeComponent.js:371
mountComponent @ ReactCompositeComponent.js:258
mountComponent @ ReactReconciler.js:46
performInitialMount @ ReactCompositeComponent.js:371
mountComponent @ ReactCompositeComponent.js:258
mountComponent @ ReactReconciler.js:46
mountComponentIntoNode @ ReactMount.js:104
perform @ Transaction.js:140
batchedMountComponentIntoNode @ ReactMount.js:126
perform @ Transaction.js:140
batchedUpdates @ ReactDefaultBatchingStrategy.js:62
batchedUpdates @ ReactUpdates.js:97
_renderNewRootComponent @ ReactMount.js:320
_renderSubtreeIntoContainer @ ReactMount.js:401
render @ ReactMount.js:422
(anonymous) @ index.js:10
__webpack_require__ @ bootstrap 9a6d4f1…:657
fn @ bootstrap 9a6d4f1…:85
(anonymous) @ fetch.js:461
__webpack_require__ @ bootstrap 9a6d4f1…:657
validateFormat @ bootstrap 9a6d4f1…:706
(anonymous) @ bundle.js:710
3个回答

问题是您已将初始状态用户指定为空,并且当您记录 user.exercises[0] 时,它会抛出该错误,因为当应用程序第一次呈现时 API 的结果尚未准备好。

在 console.log() 之前执行检查

class UserDetails extends Component{
  constructor(props) {
    super(props)
    this.state = {
      user: null,
      loading: false
    }
  }
  componentDidMount() {
    this.setState({
      loading: true
    });
    axios.get(`http://192.168.0.248:3001/api/v1/users/${this.props.match.params.id}`)
      .then(res => res.data)
      .then(user => {
        this.setState({
          user: user,
          loading: false
        });
      });
  }
  render() {
    const {loading, user} = this.state;
    if(user != null) {
      let userInfo = _.map(user, (value, prop) => {
        return { "prop": prop, "value": value };
      });

    console.log(user.exercises[0].exercise, userInfo); 
    }

    if (loading || !user) {
      return (
        <p className="user-loading">Loading ...</p>
      );
    }
    return (
      <div id="user-details">
        <div className="nav">
          <Link className="nav-back-to-list" to="/">Back to the list</Link>
        </div>
        <div id="user-details-icon">
          <img src={`/images/user_${user.gender}.png`} alt={`generic user ${user.gender} icon`} />
        </div>
        <table>
          <tbody><tr><td>Nickname</td><td>{user.nickname}</td></tr></tbody>
          <tbody><tr><td>Name</td><td>{user.name}</td></tr></tbody>
          <tbody><tr><td>Gender</td><td>{user.gender}</td></tr></tbody>
          <tbody><tr><td>Age</td><td>{user.age}</td></tr></tbody>
        </table>
        <h1>Records</h1>
      </div>
    )
  }
}
Shubham Khatri
2017-05-28

尝试将您的 axios 请求移至 componentWillMount() { ... } } 生命周期方法。

Piotr O
2017-05-28

您可能在 axios get 调用后没有获取到 React 组件实例 “this” ,请尝试以下操作:

componentDidMount() {
    this.setState({
      loading: true
    });

    let _this = this;
    axios.get(`http://192.168.0.248:3001/api/v1/users/${this.props.match.params.id}`)
      .then(res => res.data)
      .then(user => {
        _this.setState({
          user: user,
          loading: false
        });
      });
  }
Arpit Aggarwal
2017-05-28