2016-04-19 23 views
0

私は、3つのサブコンポーネントをラップする1つの親コンポーネントを必要とするクライアント向けのプロジェクトを構築することを任されています。具体的には、親コンポーネントは、次のように従うことにサブコンポーネントをレンダリング:BOTTOMReact:子コンポーネントから親コンポーネントをレンダリングする方法は?

PARENT = TOP + MIDDLE +

親コンポーネントは、アイテムのグループの1つを表します。

TOPコンポーネントには、グループ内のすべてのアイテムのリストを表示するメニューボタンがあり、ユーザーがそれらのリンクの1つをクリックすると、選択したアイテムが表示されます(PARENTは "新しいアイテム - PARENTには、選択された2番目のアイテムが最初のアイテムではなく表示されるロジックがあります)。

私はそれについて話していることが明らかではない(私はそれがすべきだと思う)場合、ここではゆるやかに言い、コードを提供することができます。

主な問題は、子コンポーネントの1つから親コンポーネントを「再レンダリング」しようとしていることです。基本的に、関連するアイテムのリストを表示するメニューボタンが表示されます。これらのアイテムの1つをクリックすると、親コンポーネントは再描画されますが、今回は選択されたアイテムが表示されます。私はこれを行う方法を知らないし、いくつかのアドバイスや助けを得ることを望んでいた。私は午前中、トピックを研究し、いくつかの役立つ方法を試してみました。

おそらく私がこれまでに取ったアプローチは、この種のタスクを達成するのには最適ではありません。いずれにしても、どんな支援も非常に役に立ちます。ありがとうございました!


EDIT:NOW

EDIT#2をWORKING:これは私はちょうどこれがコンセプトの証明とも非常に単純化されたプロトタイプ/初期バージョン(なし空想だったことを明らかにしたかったかなりの数の意見を得ているので、私たちは当時は確信が持てなかったので、このアイデアは仕事のようなものです。そんなことに取り組んでからしばらくしてきましたが、私が尋ねたそのような混乱の疑問と、その当時は何が非常に面白くて挑戦的な仕事だったのか、本当に助けに感謝します。

import React from 'react'; 

import CardHeader from 'components/CardHeader'; 
import CardContent from 'components/CardContent'; 
import CardFooter from 'components/CardFooter'; 

module.exports = React.createClass({ 

    getInitialState: function() { 
    return { 
     fullData: '', 

     //Core Card 
     userId: '', 
     cardStack: '', 
     cardId: '', 

     //Load Card 
     loadCard: '1', 

     //Optional Fields 
     name: '', 
     type: '', 
     headline: '', 
     subtitle: '', 
     ctext: '', 
     imageUrl: '', 
     price: '', 
     mapCoordinates: '', 
     logoUrl: '', 
     order: '', 
     email: '', 
     sponsorUrl: '', 
     pollId: '', 
     socialButton: '' 
    }; 
    } 
    , 

    componentWillMount: function() { 

    //fetches cardStack and card API JSON 
    /** JSON Structure: 
    [ 
    cardStack: ..., 
    cards: ... 
    ] 
    **/ 

    var fetch = function (userId, cardStackId) { 

     //AJAX 

     var json = { 
     'cardStack': {'id': '1', 'name': 'Test Card Stack', 'userID': 'O1AB0001'}, 
     'cards': [{ 
      'id': '1', 
      'name': 'Test Card 1', 
      'cardStack': '1', 
      'meta': 'meta_note', 
      'socialButton': 'twitter', 
      'sponsorUrl': 'https://iwantmyname.com/images/logo-url-shortener-droplr.png', 
      'order': 1, 
      'logoUrl': 'https://iwantmyname.com/images/logo-url-shortener-droplr.png', 
      'product': { 
      'headline': 'Headline Test', 
      'subtitle': 'Subtitle Test', 
      'ctext': 'Hello!!!!', 
      'imageUrl': 'http://the-mpas.com/wp-content/uploads/2012/04/Image-pic-54-copy.jpg', 
      'price': '20.00' 
      } 
     }, { 
      'id': '2', 
      'name': 'Test Card 2', 
      'cardStack': '1', 
      'meta': 'meta_note', 
      'socialButton': 'twitter', 
      'sponsorUrl': 'https://iwantmyname.com/images/logo-url-shortener-droplr.png', 
      'order': 2, 
      'logoUrl': 'https://iwantmyname.com/images/logo-url-shortener-droplr.png', 
      'product': { 
      'headline': 'Headline Test 2', 
      'subtitle': 'Subtitle Test 2', 
      'ctext': 'Hello 2!!!!', 
      'imageUrl': 'http://the-mpas.com/wp-content/uploads/2012/04/Image-pic-54-copy.jpg', 
      'price': '30.00' 
      } 
     }] 
     }; 

     return json; 
    }; 

    var that = this; 

    var getCard = function (cardArray, cardOrder) { 
     var card; 
     for (var key in cardArray) { 
     if (cardArray[key].order == cardOrder) { 
      card = cardArray[key]; 
     } 
     } 

     if ('product' in card) { 
     that.setState({ 
      type: 'product', 
      headline: card.product.headline, 
      subtitle: card.product.subtitle, 
      ctext: card.product.ctext, 
      imageUrl: card.product.imageUrl, 
      price: card.product.price 
     }) 
     } 
     if ('article' in card) { 
     that.setState({ 
      type: 'article', 
      headline: card.article.headline, 
      ctext: card.article.ctext 
     }) 
     } 

     if ('map' in card) { 
     that.setState({ 
      type: 'map', 
      mapCoordinates: card.map.mapCoordinates 
     }) 
     } 

     if ('relatedvideo' in card) { 
     that.setState({ 
      type: 'relatedvideo', 
      headline: card.relatedvideo.headline, 
      ctext: card.relatedvideo.ctext, 
      imageUrl: card.relatedvideo.imageUrl 
     }) 
     } 

     if ('poll' in card) { 
     that.setState({ 
      type: 'poll', 
      headline: card.poll.headline, 
      subtitle: card.poll.subtitle, 
      pollId: card.poll.pollId 
     }) 
     } 

     if ('imagegallery' in card) { 
     that.setState({ 
      type: 'imagegallery', 
      headline: card.imagegallery.headline, 
      ctext: card.imagegallery.ctext, 
      imageUrl: card.imagegallery.imageUrl 
     }) 
     } 

     if ('profile' in card) { 
     that.setState({ 
      type: 'profile', 
      headline: card.profile.headline, 
      ctext: card.profile.ctext, 
      imageUrl: card.profile.imageUrl 
     }) 
     } 

     if ('newsletter' in card) { 
     that.setState({ 
      type: 'newsletter', 
      email: card.newsletter.email 
     }) 
     } 
     return card; 
    }; 

//Entry Point HERE 
    var userId = 'O1AB0001', cardStackId = 1; 
    var json = fetch(userId, cardStackId); 
    var myCard = getCard(json.cards, this.state.loadCard); 

//Set core data 
    this.setState({ 

     //fulldata 
     fullData: json, 

     //card stack 
     userId: json.cardStack.name, 
     cardStack: json.cardStack.id, 

     //card 
     cardId: myCard.id, 
     socialButton: myCard.socialButton, 
     order: myCard.order, 
     sponsorUrl: myCard.sponsorUrl, 
     logoUrl: myCard.logoUrl, 
     meta: myCard.meta, 
     name: myCard.name 
    }); 
    }, 

    setNew: function (nextState) { 

    var nsFullData = nextState.fullData; 
    var nsCards = nsFullData.cards; 
    var nsCardStack = nsFullData.cardStack; 

    var that = this; 
    var getCard = function (cardArray, cardOrder) { 
     var card; 
     for (var key in cardArray) { 
     if (cardArray[key].order == cardOrder) { 
      card = cardArray[key]; 
     } 
     } 

     if ('product' in card) { 
     that.setState({ 
      type: 'product', 
      headline: card.product.headline, 
      subtitle: card.product.subtitle, 
      ctext: card.product.ctext, 
      imageUrl: card.product.imageUrl, 
      price: card.product.price 
     }) 
     } 
     if ('article' in card) { 
     that.setState({ 
      type: 'article', 
      headline: card.article.headline, 
      ctext: card.article.ctext 
     }) 
     } 

     if ('map' in card) { 
     that.setState({ 
      type: 'map', 
      mapCoordinates: card.map.mapCoordinates 
     }) 
     } 

     if ('relatedvideo' in card) { 
     that.setState({ 
      type: 'relatedvideo', 
      headline: card.relatedvideo.headline, 
      ctext: card.relatedvideo.ctext, 
      imageUrl: card.relatedvideo.imageUrl 
     }) 
     } 

     if ('poll' in card) { 
     that.setState({ 
      type: 'poll', 
      headline: card.poll.headline, 
      subtitle: card.poll.subtitle, 
      pollId: card.poll.pollId 
     }) 
     } 

     if ('imagegallery' in card) { 
     that.setState({ 
      type: 'imagegallery', 
      headline: card.imagegallery.headline, 
      ctext: card.imagegallery.ctext, 
      imageUrl: card.imagegallery.imageUrl 
     }) 
     } 

     if ('profile' in card) { 
     that.setState({ 
      type: 'profile', 
      headline: card.profile.headline, 
      ctext: card.profile.ctext, 
      imageUrl: card.profile.imageUrl 
     }) 
     } 

     if ('newsletter' in card) { 
     that.setState({ 
      type: 'newsletter', 
      email: card.newsletter.email 
     }) 
     } 
     return card; 
    }; 

    var myCard = getCard(nsCards, this.state.loadCard); 

    this.setState({ 

     //fulldata 
     fullData: nsFullData, 

     //card stack 
     userId: nsCardStack.name, 
     cardStack: nsCardStack.id, 

     //card 
     cardId: myCard.id, 
     socialButton: myCard.socialButton, 
     order: myCard.order, 
     sponsorUrl: myCard.sponsorUrl, 
     logoUrl: myCard.logoUrl, 
     meta: myCard.meta, 
     name: myCard.name 
    }); 
    }, 

    componentWillUpdate: function (nextProps, nextState) { 
    if (nextState.loadCard !== this.state.loadCard) { 
     this.setNew(nextState); 
    } 
    }, 

    render: function() { 

    return (
     <div className='sg-cardBase'> 
     <div className='sg-cardHeaderSection'> 
      <CardHeader setLoadCard={i => this.setState({loadCard: i})} data={this.state}/> 
     </div> 
     <div className='sg-cardContentSection'> 
      <CardContent data={this.state}/> 
     </div> 
     <div className='sg-cardFooterSection'> 
      <CardFooter data={this.state}/> 
     </div> 
     </div> 
    ); 
    } 
}); 
+0

:だから真ん中には、親からのビューとしてcurrentViewを取得し、それが目的のビューを再描画します。主な問題は、Stateが変更されたときにBaseが単に再レンダリングしないことです。ドキュメント、https://facebook.github.io/react/docs/component-specs.htmlは、ComponentWillUpdateでsetStateにしないと言っています... –

+0

私の主な障害は、私のメニュー項目をクリックした後に "これは未定義です " –

答えて

3

親コンポーネントの状態を変更する子コンポーネントにコールバックを渡す必要があります。親は、その状態に基づいて再レンダリングすることができます。例えば:あなたのケースで

var Parent = React.createClass({ 
    getInitialState: function() { 
    return { index: 1 }; 
    }, 
    render: function() { 
    return <div> 
     <Child setIndex={i => this.setState({index: i})}/> 
     <p>{this.state.index}</p> 
     </div> 
    } 
}) 

var Child = React.createClass({ 
    render: function() { 
    <button onClick={() => this.props.setIndex(5)}/> 
    } 
}); 

、現在選択されているアイテムは、親コンポーネントの状態で保存されるべきで、それが選択した項目を変更することができるように、コールバックが上位コンポーネントに渡されます。

+0

こんにちは!提案していただきありがとうございます。状況は私が思っていたものよりやや厄介です - 私たちが使用しているのは、私たちのドメインと4つの反応コンポーネント(Top、Middle、Bottom、およびBase)の多型のための多次元配列です。何が起こる必要があるかは、Topの新しい項目を選択することによって、新しい項目のデータがBaseを通して子コンポーネントに渡されるということです。さて、私たちがやってきたのは、Baseの状態を使って他の3つのコンポーネントのそれぞれにプロパティを渡そうとすることです。しかし、あなたが作った提案は、堅実ではあるが、現在の取り決めを考えれば明らかに役に立たない。 –

+0

(続き)コールバックで状態を変更しているためです。しかし、コールバックはいくつかのsetState呼び出しをトリガし、その後同じデータを新しいレンダリングロジックに渡す必要があります。 –

+0

私は上記のいくつかのコードを追加しました... –

1

メニューに応じて上下が変わらず、中央が変わるとします。

トップは親からコールバックを取得します。一番上のオプションが選択されると、コールバックchangeCurrentViewが呼び出され、currentViewについて通知されます。コールバックchangeCurrentViewは親状態を設定し、renderメソッドを呼び出します。

親のレンダリングミドルを変更できるようになりましたが、ミドルが異なるビューを再レンダリングすることをお勧めします。上記編集されたコメントをご覧ください

class Parent extends React.Component { 
 

 
    constructor(props) { 
 
    super(props); 
 
     
 
    this.state = { 
 
     currentView: 0 
 
    }; 
 
     
 
    this.changeCurrentView = this.changeCurrentView.bind(this); 
 
    } 
 
    
 
    changeCurrentView(currentView) { 
 
    this.setState({ 
 
     currentView 
 
    }); 
 
    } 
 
    
 
    render() { 
 
    return (
 
     <div> 
 
     <Top changeView={ changeCurrentView } /> 
 
     
 
     <Middle currentView = { this.state.currentView } /> 
 
     
 
     <Bottom /> 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
const views = [ 
 
    <View1 />, 
 
    <View2 />, 
 
    <View3 /> 
 
]; 
 

 
const Middle = ({ currentView }) => (
 
    <div>{ 
 
    views[currentView]; 
 
    </div> 
 
);

+0

こんにちは!提案していただきありがとうございます。状況は私が思っていたものよりやや厄介です - 私たちが使用しているのは、私たちのドメインと4つの反応コンポーネント(Top、Middle、Bottom、およびBase)の多型のための多次元配列です。何が起こる必要があるかは、Topの新しい項目を選択することによって、新しい項目のデータがBaseを通して子コンポーネントに渡されるということです。さて、私たちがやってきたのは、Baseの状態を使って他の3つのコンポーネントのそれぞれにプロパティを渡そうとすることです。しかし、あなたが作った提案は、堅実ではあるが、現在の取り決めを考えれば明らかに役に立たない。 –

+0

(続き)コールバックで状態を変更しているためです。しかし、コールバックはいくつかのsetState呼び出しをトリガし、新しいデータを同じレンダリングロジックに渡す必要があります –

+0

私はもう少し上に追加しました... –

関連する問題