2016-04-19 2 views
0

Мне поручили создать проект для клиента, который влечет за собой один родительский компонент, который обертывает три подкомпонента. В частности, родительский компонент представляет компоненты суб в быть в соответствии со следующим способом:React: Как визуализировать родительский компонент из дочернего компонента?

РОДИТЕЛЬ = TOP + БЛИЖНИЙ + НИЖНИЙ

компонент Родитель представляет собой один из группы элементов.

В верхнем компоненте есть кнопка меню, которая отображает список всех элементов в группе с намерением, который пользователь должен щелкнуть по одной из этих ссылок, отобразится выбранный элемент (PARENT будет «повторно отображать» «новый элемент - в PARENT есть логика, которая приведет к отображению выбранного, второго, элемента, а не первого).

Я говорю здесь свободно и могу предоставить код, если то, о чем я говорю, не ясно (я думаю, это должно быть).

Основная проблема, с которой я сталкиваюсь, заключается в попытке «повторно отобразить» родительский компонент из одного из дочерних компонентов. По существу, появляется кнопка меню, отображающая список связанных элементов. При нажатии на один из этих элементов следует повторно отобразить родительский компонент, но на этот раз отобразить выбранный элемент. Я не знаю, как это сделать, и надеялся получить совет или помощь. Я провел утро, исследуя эту тему, и попробовал несколько предложенных способов безрезультатно.

Возможно, подход, который я сделал до сих пор, не является лучшим решением для выполнения такого рода задач. В любом случае любая помощь была бы очень полезной. Спасибо!


EDIT: СЕЙЧАС РАБОТАЮ

EDIT # 2: Так как это не получил довольно много взглядов, которые я просто хотел уточнить, что это доказательство концепции, а также очень упрощенный прототип/ранняя версия (не фантазии транспиляция и т. д. - эта идея может работать как раз ... поскольку мы не были уверены в то время). Прошло некоторое время с тех пор, как я работал над чем-то подобным, но я очень ценю всю помощь для такого запутанного вопроса, который я задал, и что было в то время очень интересной и сложной задачей.

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

Пожалуйста, смотрите отредактированный комментарий выше. Основная проблема заключается в том, что Base просто не будет повторно отображаться при изменении состояния. Документы, https://facebook.github.io/react/docs/component-specs.html, скажем, не для setState в ComponentWillUpdate ... –

+0

Основным препятствием, которое я получаю, является то, что после нажатия на мой пункт меню я получаю " это 'undefined " –

ответ

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

Привет! Спасибо за предложение. Ситуация немного сложнее, чем я думал - то, что мы используем, - это многомерный массив для полиморфизма в нашей области и четыре реагирующих компонента (верхний, средний, нижний и базовый). Что должно произойти, так это то, что, выбрав новый элемент в верхней части, данные нового элемента передаются через базу в дочерние компоненты. Теперь мы пытаемся использовать состояние Base для передачи свойств каждому из трех других компонентов. Но предложение, сделанное вами, несмотря на то, что оно твердое, по-видимому, не помогает нам дать текущую договоренность. –

+0

(Продолжение), потому что мы меняем состояние с помощью обратного вызова. Но обратный вызов должен вызывать несколько вызовов setState, а затем передавать эти новые данные через одну и ту же логику визуализации. –

+0

Я добавил код выше ... –

1

Я предполагаю, что верх и низ остаются, а середина изменяется в соответствии с меню.

Верх получает обратный вызов от родителя. Когда опция выбрана в верхней части, она вызывает обратный вызов changeCurrentView и уведомляет ее об currentView. Обратный вызов changeCurrentView устанавливает родительское состояние, вызывая метод визуализации.

Теперь вы можете изменить середину рендера в родительском, но я предлагаю, чтобы середина повторно отображала разные виды.Так средний получает currentView как вид из родителей, и он вновь оказывает желаемый вид:

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

Привет! Спасибо за предложение. Ситуация немного сложнее, чем я думал - то, что мы используем, - это многомерный массив для полиморфизма в нашей области и четыре реагирующих компонента (верхний, средний, нижний и базовый). Что должно произойти, так это то, что, выбрав новый элемент в верхней части, данные нового элемента передаются через базу в дочерние компоненты. Теперь мы пытаемся использовать состояние Base для передачи свойств каждому из трех других компонентов. Но предложение, сделанное вами, несмотря на то, что оно твердое, по-видимому, не помогает нам дать текущую договоренность. –

+0

(Продолжение), потому что мы меняем состояние с помощью обратного вызова. Но обратный вызов должен инициировать несколько вызовов setState, а затем передавать эти новые данные через одну и ту же логику визуализации. –

+0

. Я добавил немного больше ... –

Смежные вопросы