2017-05-28 75 views
0

UPDATE我可以在render()函数的return语句中正常访问所有内容。 F.e user.exercises [0] .exercise.name输出“蹲”。这就是为什么我更难以理解为什么在return语句之前我无法访问它以创建一个将值映射到表的函数。 UPDATE无法访问React对象或数组中的特定键

我似乎有访问React中特定键的问题。我尝试读取的对象是从mongodb的后端API请求的,并以JSON格式输出。我已经尝试通过lodash将对象映射到数组后访问它,但问题是相同的。我可能只是读对象错误并指定了错误的键,但我看不到它。我没有任何问题console.logging整个JSON或顶部键,通过写{user.name} f.e“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": [] 
     } 
     } 
    ] 
    } 

而且阵营代码:

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(用户);

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 

回答

0

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

+0

不幸的是没有改变。 –

+0

并设置'user'作为axios调用的响应'然后(res => {this.setState({user:res.data,loading:false});}' –

+0

我不知道我是否理解你我认为你没有从axios请求中得到任何正确的数据,但是我和我在记录整个响应时没有任何问题,但是当试图访问练习中的值时,我一直在错误我更新了记录整个信息和userInfo变量时获得的数据的问题 –

0

也许你没有得到反应组件实例“这个”axios get调用,试试这个:

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 
     }); 
     }); 
    } 
+0

我不知道我是否明白你的建议是正确的,但我相信你认为我没有得到任何正确的但是我确实没有记录整个响应的任何问题,但是当尝试访问练习中的值时,我总是收到错误信息,并且使用记录整个信息时获得的数据更新了问题, userInfo变量。 –

+0

@MateuszMysiak I无法读取您的React Code中的'Exercises'。 – Arpit

+0

的确,这就是问题所在。每次尝试时,我都会得到错误练习为空。也许这是数据结构中的问题?不过,我基本上复制了pokeapi.co/api/v2/pokemon/1示例。 –

1

问题是,你已分配的初始状态的用户为空,当您登录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> 
    ) 
    } 
} 
+0

它的行为完全一样。问题不在于用户值本身是空的,因为axios将它从componentDidMount中的后端设置为JSON,并且对console.log(user)没有任何问题。唯一的问题是当我尝试记录更深的用户,如user.exercises [0]或user.exercises [0] .exercise或user.exercise [0] .exercise.name。基本上任何练习的关键。 –

0

确定。因此,在通过不同类型的数组循环/映射后,我终于找到了一个解决方案,并希望与任何可能会遇到这个愚蠢问题的人分享。

基本上,Shubham Khatri是正确的建议做一个空检查(是否存在一个值)。但是,它是在错误的键上完成的。由于我的数据库中总是有一些用户,所以我们不需要对它执行空检查。我需要做的是对“exercices”数组内的“records”数组进行空值检查。并非所有用户都提交了结果,因此在循环/映射时没有数据可以执行操作。在添加检查之后,如果每个用户中有任何记录,则该应用可以正常显示那些具有这些记录的用户的结果,并显示没有发布任何结果的“没有结果显示”。

我最近了解到,学习API是需要哪些密钥的好习惯,这样我们就不必对它们执行空检查,也不需要哪些密钥,并且可能会缺少一些密钥结果,我们应该绝对做空检查。或者,如果我们建立自己的API,我们应该指定自己,哪些将在每个对象中出现,哪些是可选的。