2016-12-20 12 views
15

私は様々な子コンポーネントのデータを取り込むための素敵なApiWrapperコンポーネントを作ろうとしています。 https://jsfiddle.net/vinniejames/m1mesp6z/1/親子状態の変更後に子要素が反応しないようにします

class ApiWrapper extends React.Component { 

    constructor(props) { 
    super(props); 

    this.state = { 
     response: { 
     "title": 'nothing fetched yet' 
     } 
    }; 
    } 

    componentDidMount() { 
    this._makeApiCall(this.props.endpoint); 
    } 

    _makeApiCall(endpoint) { 
    fetch(endpoint).then(function(response) { 
     this.setState({ 
     response: response 
     }); 
    }.bind(this)) 
    } 

    render() { 
    return <Child data = { 
     this.state.response 
    } 
    />; 
    } 
} 

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

    render() { 
    console.log(this.state.data, 'new data'); 
    return (<span> { 
     this.state.data.title 
    } < /span>); 
    }; 
} 

var element = < ApiWrapper endpoint = "https://jsonplaceholder.typicode.com/posts/1"/> ; 

ReactDOM.render(
    element, 
    document.getElementById('container') 
); 

をしかし、何らかの理由で、子コンポーネントをするとき、親の状態の変更を更新していないようです。私が読んだすべてのものから、これは動作するはずです。

ここに何か不足していますか?

答えて

51

コードには2つの問題があります。

子コンポーネントの初期状態は、小道具から設定されています。このSO Answerから引用

this.state = { 
    data: props.data 
}; 

getInitialState(我々の場合でconstuctor)メソッドのみが最初に呼び出されているためpropとしてコンポーネントにintial状態を渡す

抗パターン あります コンポーネントが描画される時刻。決してもっと。コンポーネントは、それがレンダリングされた最初の時からの状態 を維持しますので、あなたがいる場合 コンポーネントがpropとして異なる値を渡すことを再レンダリング、ということを意味し、コンポーネント は、それに応じて反応しなくなります。非常にエラーが発生しやすいです。

したがって、このような状況を回避できない場合は、componentWillReceivePropsメソッドを使用して新しい小道具を待ち受けることが理想的です。

子コンポーネントに以下のコードを追加すると、子コンポーネントの再レンダリングに関する問題が解決されます。

componentWillReceiveProps(nextProps) { 
    this.setState({ data: nextProps.data }); 
} 

2番目の問題はfetchです。

_makeApiCall(endpoint) { 
    fetch(endpoint) 
    .then((response) => response.json()) // ----> you missed this part 
    .then((response) => this.setState({ response })); 
} 

そして、ここでの作業フィドルです:https://jsfiddle.net/o8b04mLy/

+0

「知っているならば、[小道具に基づいて状態を初期化する](https://facebook.github.io/react/docs/react-component.html#constructor)は大丈夫ですあなたは何をしているのですか? 'nextProp'が' componentWillReceiveProps(nextProps) 'なしで再レンダリングを引き起こさないという事実に加えて、propを使って状態を設定することには、他の弱点がありますか? –

+2

私が知る限り、他には欠点はありません。しかし、あなたのケースでは、子コンポーネントの内部に状態があることを明確に避けることができます。親はちょうど小道具としてデータを渡すことができ、親が新しい状態で再レンダリングするとき、子供はまた新しい小道具で再レンダリングするでしょう。実際には子供の中の状態を維持することはここでは不要です。純粋なコンポーネントFTW! –

+0

私の問題が解決した理由を説明してくれてありがとう – OmarBizreh

0

変更が必要なことがいくつかあります。

fetchが応答を受け取ると、それはjsonではありません。 私はこのjsonをどうやって得ることができるのかを探していましたが、これはlinkでした。

もう一方の側では、constructor関数が1回だけ呼び出されると考える必要があります。

したがって、<Child>のデータを取得する方法を変更する必要があります。 https://jsfiddle.net/emq1ztqj/

私はそれが役に立てば幸い:

ここで、私は、サンプルコードを残しました。

+0

ありがとうございました。あなたが作った例を見ても、子どもは決して更新しないようです。子供がデータを受け取る方法を変更する方法に関する提案はありますか? –

+2

本当ですか?''コンポーネントが 'https:// jsonplaceholder.typicode.com/posts/1'から新しいデータを取得して再レンダリングすることがわかりました。 – slorenzo

+1

はい、OSXで動作しています。 iOSがStackExchangeアプリブラウザで再レンダリングを起動していない –

関連する問題