2017-05-03 2 views
1

J'ai actuellement un problème pour créer mon application ReactJS. J'ai un tableau qui prend cette forme:ReactJS - Passer les références entre les frères et sœurs

[{ 
    _id: 123456, 
    ... 
    children: [ 
     { 
     _id: 568, 
     ... 
     children: [...] // and so on, recursively 
      }, 
     .... 
    ] 
}] 

Cette architecture doit être rendu comme certains « arbre de l'évolution », comme dans:

| item | => | item's first child | => | first child's first child | .. 
|  | => | item's second child | 

Si chaque « élément » ou « enfant » est un composant (appelé EvolutionStep), et chaque flèche "=>" est un autre composant (appelé EvolutionArrow). Nous avons donc trois composantes:

Evolution Chain => parent component, that renders 
Evolution Step => containing the evolution props (name, etc) 
Evolution Arrow => linking one step to one of it's children. 

L'évolution flèche doit pointer dans le sens où la prochaine évolution étape est rendue (dans l'exemple, la première flèche entre l'article et le premier enfant de l'article pointera directement, mais si le La position du premier enfant de l'élément est comme {top: -20px}

Pour ce faire, chaque étape d'évolution, lorsqu'elle est rendue, appelle une fonction dans Evolution Chain pour ajouter sa référence à l'état local. La flèche, une fois rendue, reçoit la référence à l'étape d'évolution vers laquelle elle doit pointer Le problème est que l'accessoire d'Evolution Arrow est toujours défini ...

Je ne sais pas si je me suis expliqué correctement, alors voici mon code. Notez que si dans la classe Evolution Arrow vous mettez un fichier console.log (this.props.references), il est toujours indéfini.

Merci d'avance pour votre aide!

import PropTypes from 'prop-types'; 
import React from 'react'; 

class EvolutionStep extends React.Component { 

    componentDidMount() { 
     this.props.mountCallable(this.props.step._id, this); 
    } 

    render() { 
     return (
      <div style={{width: this.props.width + "%"}} data-identifier={this.props.step._id}>step</div> 
     ); 
    }; 

} 

class EvolutionArrow extends React.Component { 

    render() { 
     console.log(this.props); 
     return (
      <div>arrow</div> 
     ); 
    } 
} 

const EvolutionChain = class EvolutionChain extends React.Component { 

    constructor(props) { 
     super(props); 

     this.processStack.bind(this); 
     this.stepDidMount.bind(this); 
     this.preRender.bind(this); 

     this.state = { 
      cols: 0, 
      chainData: [], 
      refs: {} 
     }; 
    } 

    componentDidMount() { 
     this.processStack(); 
    } 

    stepDidMount(step_id, element) { 
     let refs = this.state.refs; 

     if (undefined == typeof(refs[step_id])) { 
      refs[step_id] = element; 
      this.setState({refs: refs}); 
     } 
    } 

    processStack() { 
     if (null == this.props.chain) { 
      return null; 
     } 

     let stack = [this.props.chain.children[0]]; 
     let results = []; 

     while (stack.length > 0) { 
      const current = stack.pop(); 
      // build current element 
      results.push({type: 'step', props: {step: current} }); 
//   results.push(<EvolutionStep key={current._id} ref={(step) => this.addRef(current._id, step)} step={current} width={(100/this.state.cols)}/>); 
      this.setState({cols: this.state.cols + 1}); 
      if (current.children.length > 0) { 
       let arrows = []; 
       current.children.map((item) => { 
        arrows.push({pointsTo: item._id}); 
        //arrows.push(<EvolutionArrow pointsTo={item._id} references={this.state.refs}/>); 
       }); 
//    results.push(<div className="arrow" width={(100/this.state.cols)}>{arrows}</div>); 
       results.push({type: 'arrows', arrows: arrows}); 
       this.setState({cols: this.state.cols + 1}); 
       stack = current.children; 
      } 
     } 

     results.reverse(); 
     this.setState({chainData: results}); 
    } 

    preRender() { 
     var components = []; 
     this.state.chainData.map((item) => { 
      switch (item.type) { 
       case 'step': 
        components.push(<EvolutionStep key={item.props.step._id} {...item.props} mountCallable={(step_id, elem) => this.stepDidMount(step_id, elem)}/>); 
        break; 
       case 'arrows': 
        let arrows = []; 
        item.arrows.map((arrow) => { 
         arrows.push(<EvolutionArrow pointsTo={arrow.pointsTo} references={this.state.refs[arrow.pointsTo]} />); 
        }); 
        components.push(<div className="arrow">{arrows}</div>); 
        break; 
      } 
     }); 

     return components; 
    } 

    render() { 

     let toRender = this.preRender(); 
     return (
      <div className="container-fluid"> 
       {toRender} 
      </div> 
     ); 
    } 

}; 

/** TODO: PropTypes **/ 

export default EvolutionChain; 
+0

est donc 'stepDidMount' s'appeler ou non? –

+0

'stepDidMount' est en effet appelé, et passe l'élément et le droit' step_id'. Il semble que la mise à jour de l'état ne soit pas propagée aux enfants, car le prop de 'references' de tous les composants' EvolutionArrow' reste 'indéfini ' – Lucio

Répondre

0

Fixé! Tout ce que je devais faire est envelopper undefined entre guillemets dans stepDidMount, sinon la condition était toujours faux ...

0

refs et componentDidMount() faire l'affaire.

Le code suivant m'aide à configurer la communication entre deux frères et sœurs. L'installation est effectuée dans leur parent pendant les appels render() et componentDidMount(). Il est basé sur https://reactjs.org/docs/refs-and-the-dom.html

class App extends React.Component<IAppProps, IAppState> { 
    private _navigationPanel: NavigationPanel; 
    private _mapPanel: MapPanel; 

    constructor() { 
     super(); 
     this.state = {}; 
    } 

    // `componentDidMount()` is called by ReactJS after `render()` 
    componentDidMount() { 
     // Pass _mapPanel to _navigationPanel 
     // It will allow _navigationPanel to call _mapPanel directly 
     this._navigationPanel.setMapPanel(this._mapPanel); 
    } 

    render() { 
     return (
      <div id="appDiv" style={divStyle}> 
       // `ref=` helps to get reference to a child during rendering 
       <NavigationPanel ref={(child) => { this._navigationPanel = child; }} /> 
       <MapPanel ref={(child) => { this._mapPanel = child; }} /> 
      </div> 
     ); 
    } 
}