2017-09-27 9 views
3

私はJSONを解析しているreduxコンポーネントを持っていますが、ネストされた子オブジェクトを取得する方法はわかりません。私はmapStateToPropsの動作を正しく理解しているとは思わない。React/Redux mapStateToProps with nested JSON

コンソールログは、子オブジェクトをダンプしているが、私はservices.nameにアクセスしようとしたとき、私は

"Cannot read property 'name' of undefined"

を取得し、誰かが私がここでプロパティをマップする方法を理解するのに役立つことはできますか? APIの一番下にあるJSONの例を紹介しました。

サービス-list.js

import React, { Component } from 'react'; 
import { connect } from 'react-redux'; 
import * as actions from '../actions'; 

class ServicesList extends Component { 

    componentDidMount(){ 
    this.props.fetchServices(); 
    } 

    render() { 
    //console.log('render called in ServicesList component'); 
    return (
     <table className='table table-hover'> 
     <thead> 
      <tr> 
      <th>Service Name</th> 
      </tr> 
     </thead> 
     <tbody> 
      {this.props.services.map(this.renderServices)} 
     </tbody> 
     </table> 
    ); 
    } 

    renderServices(data) { 
    console.log(data.services); 
    const name = data.services.name; 
    return(
     <tr key={name}> 
     <td>{name}</td> 
     </tr> 
    ); 
    } 
} 

function mapStateToProps({services}) { 
    return { services }; 
} 

export default connect(mapStateToProps, actions)(ServicesList); 

私のJSONは、次のようになります。

{ 
    "services": [ 
    { 
     "name": "redemption-service", 
     "versions": { 
      "desired": "20170922_145033", 
      "deployed": "20170922_145033" 
     }, 
     "version": "20170922_145033" 
    }, { 
     "name": "client-service", 
     "versions": { 
      "desired": "20170608_094954", 
      "deployed": "20170608_094954" 
     }, 
     "version": "20170608_094954" 
    }, { 
     "name": "content-rules-service", 
     "versions": { 
      "desired": "20170922_130454", 
      "deployed": "20170922_130454" 
     }, 
     "version": "20170922_130454" 
    } 
    ] 
} 

は最後に、私はここaxios.getを公開する作用を有する:

import axios from 'axios'; 

const ROOT_URL=`http://localhost:8080/services.json`; 

export const FETCH_SERVICES = 'FETCH_SERVICES'; 

export function fetchServices(){ 
    const url = `${ROOT_URL}`; 
    const request = axios.get(url); 

    return{ 
    type: FETCH_SERVICES, 
    payload: request 
    }; 
} 
+0

あなた 'constの名前= data.services.name;' 'constの名前= data.nameでなければなりません;' – Panther

+0

、あなたはbcoz services' 'の上にマッピングし、それぞれにされていますループすると、 'renderServices'関数内に単一の' service'が得られます。 – Panther

+0

これは、renderServicesを1回だけ呼び出しています。私が理解できないことは、名前が付けられていないときに次のオブジェクトをどのようにマップするかです。 –

答えて

2

私はthis.props.fetchServices()servicesレデューサーを更新し、01 mapStateToPropsを介してを支柱として使用します。
これが正しい場合は、componentWillMountの内部にフェッチしていることに注意してください。これはBIGではありません。 componentWillMount DOCSから
引用:

Avoid introducing any side-effects or subscriptions in this method.

あなたはcomponentDidMountでデータをフェッチする必要があります。

さらに、ajaxリクエストからデータを取得するまで、レンダリングメソッドは呼び出されないと考えられます。あなたが参照してください、反応はあなたのAJAX呼び出しがデータを取得するのを待つことはありませんrenderメソッドが呼び出されるので、最初のrendermapservices(空の配列を持っていますあなたの減速機の初期状態として私は仮定します)。
次に、あなたのrenderServices機能は、あなたがdata.services.nameあなたにアクセスしようとするとdatadata.servicesとして空の配列が故に実際undefinedで取得するには、エラーを取得する:

"Cannot read property 'name' of undefined"

はちょうどあなたのレンダリングに条件を使用します。

<tbody> 
    {this.props.services && this.props.services.map(this.renderServices)} 
</tbody> 


あなたのコメントへのフォローアップとして、objectアレイ上では.mapが機能します。実際にはservices.mapの代わりにservices.services.map(...)にマップする必要がありますが、まだ存在するかどうかを確認する必要があります。
私はあなたのコードで実例を作成しました。私はreduxとajaxリクエストは含まれていませんでしたが、私は同じデータを使用していました.2番目のレンダリングでServicesListしか渡さないので、あなたが直面しているシナリオ。
私は遅延を模倣するためにタイムアウトを追加しました+ローディングインジケータを追加して、条件付きレンダリングで何ができるかを示しました。

const fakeData = { 
 
    services: [ 
 
    { 
 
     name: "redemption-service", 
 
     versions: { 
 
     desired: "20170922_145033", 
 
     deployed: "20170922_145033" 
 
     }, 
 
     version: "20170922_145033" 
 
    }, 
 
    { 
 
     name: "client-service", 
 
     versions: { 
 
     desired: "20170608_094954", 
 
     deployed: "20170608_094954" 
 
     }, 
 
     version: "20170608_094954" 
 
    }, 
 
    { 
 
     name: "content-rules-service", 
 
     versions: { 
 
     desired: "20170922_130454", 
 
     deployed: "20170922_130454" 
 
     }, 
 
     version: "20170922_130454" 
 
    } 
 
    ] 
 
}; 
 

 
class ServicesList extends React.Component { 
 
    componentDidMount() { 
 
    this.props.fetchServices(); 
 
    } 
 

 
    render() { 
 
    const { services } = this.props; 
 

 
    return (
 
     <table className="table table-hover"> 
 
     <thead> 
 
      <tr> 
 
      <th>Service Name</th> 
 
      </tr> 
 
     </thead> 
 
     <tbody> 
 
      {services.services ? (
 
      services.services.map(this.renderServices) 
 
     ) : (
 
      this.renderLoader() 
 
     )} 
 
     </tbody> 
 
     </table> 
 
    ); 
 
    } 
 

 
    renderLoader() { 
 
    return (
 
     <tr> 
 
     <td>Loading...</td> 
 
     </tr> 
 
    ); 
 
    } 
 

 
    renderServices(data) { 
 
    const name = data.name; 
 
    return (
 
     <tr key={name}> 
 
     <td>{name}</td> 
 
     </tr> 
 
    ); 
 
    } 
 
} 
 

 
class App extends React.Component { 
 
    constructor(props) { 
 
    super(props); 
 
    this.state = { 
 
     data: {} 
 
    }; 
 
    this.fetchServices = this.fetchServices.bind(this); 
 
    } 
 

 
    fetchServices() { 
 
    setTimeout(() => { 
 
     this.setState({ data: { ...fakeData } }); 
 
    }, 1500); 
 
    } 
 

 
    render() { 
 
    const { data } = this.state; 
 
    return (
 
     <div> 
 
     <ServicesList services={data} fetchServices={this.fetchServices} /> 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
ReactDOM.render(<App />, document.getElementById("root"));
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<div id="root"></div>

+0

代わりに、代わりにcomponentDidMountでフェッチを送信するように更新しましたが、同じ問題が残っています...データが戻ってきました(30レコード全体が記録されているのがわかります)。しかし、JSONトップレベルのレコードが1つあります。問題は、トップレコードをスキップして子供をマッピングするにはどうすればいいですか? –

+0

'componentDidMount'は解決策ではありませんでした。私は' componentWillMount'でそれを行うのが悪い習慣であるため、これを言いました。私はより多くの説明と実際の例で私の答えを更新しました、私はこれが正しい道にあなたを設定する必要がありますと思う。 :) –

+0

スーパー!助けてくれてありがとう。これはうまくいった。 –