2017-09-11 1 views
0

Je développe des SPAs dans React et j'ai rencontré plusieurs fois ce problème; Je l'ai finalement résolu de manière UGLY comme celle affichée dans le code ci-dessous. Je sens que je manque quelque chose d'évident mais je n'arrive pas vraiment à trouver un moyen plus élégant (ou même juste) d'obtenir le même résultat, pouvez-vous m'aider?Boucler la réponse dynamique du serveur dans React render

class Leaderboard extends React.Component { 
    constructor(props) { 
    super(props); 
    this.state={ 
     lb:{}, 
     leaderboard:"" 
    }; 
    this.leaderboardGet = this.leaderboardGet.bind(this); 
    this.leaderboardSet = this.leaderboardSet.bind(this); 
    this.lblooper = this.lblooper.bind(this); 
    this.lbconstruct = this.lbconstruct.bind(this); 
    } 


    leaderboardGet(callback){ //server call which returns data 
    axiosCall.get('leaderboard.php',{params:{user:this.props.user}}) 
    .then((response)=>{ 
     var arr=response.data; 
     callback(arr); 
    }) 
    .catch((error)=>{ 
     console.log(error); 
    }) 
    } 
    leaderboardSet(a){ //puts in lb object the results of the server call and calls lb looper 
    this.setState({lb: a}); 
    this.lblooper(); 
    } 
    componentWillMount(){ 
    this.leaderboardGet(this.leaderboardSet); 
    } 

    lblooper(){ //the ugliness itself: loops the data in lb object, and pushes it into an "html string" in lblconstruct function 
    Object.entries(this.state.lb).forEach(
     ([key, value]) => this.lbconstruct(`<div class="leaderblock ${value.active}"><div class="leaderscore">${value.pos}) </div><div class="leadername">${value.usrname}</div><div class="leaderscore dx">${value.pts} <i class='fa fa-trophy'></i></div></div>`) 
    ); 
    } 
    lbconstruct(s){ 
    this.setState({leaderboard:this.state.leaderboard+=s}); 
    } 

    render() { 
    return (
     <div> 
     <div className="leaderboard"> 
      <div dangerouslySetInnerHTML={{__html:this.state.leaderboard}}/> 
     </div> 
     </div> 
    ); 
    } 
} 

En gros, si j'ai données du serveur qui doit être mis à l'intérieur format html pour les boucles N, je ne pouvais pas trouver un autre moyen, donc je me demande où je me trompe.

Répondre

3

sortie vos données en réagissent éléments dans votre rendu la fonction:

class Leaderboard extends React.Component { 
    constructor(props) { 
    super(props); 
    this.state={ 
     leaderboard: {}, 
    }; 
    } 

    componentWillMount(){ 
    axiosCall.get('leaderboard.php', { params: { user:this.props.user } }) 
     .then(response => this.setState({ leaderboard: response.data })) 
     .catch(console.log) 
    } 

    render() { 
    const { leaderboard } = this.state 
    return (
     <div> 
     <div className="leaderboard"> 
      // .map returns a new array, which we have populated with the react elements 
      { Object.keys(leaderboard).map((key) => { 
      const value = leaderboard[key] 
      return (
       <div key={key} class={`leaderblock ${value.active}`}> 
       <div class="leaderscore">{value.pos}</div> 
       <div class="leadername">{value.usrname}</div> 
       <div class="leaderscore dx"> 
        {value.pts} 
        <i class='fa fa-trophy'></i> 
       </div> 
       </div> 
      ) 
      }) } 
     </div> 
     </div> 
    ); 
    } 
} 

Faire comme ceci est ce qui permet de réagir au travail, il peut garder une trace de ce que les éléments sont là, et si vous ajoutez un, il peut voir la différence et ajoute simplement l'élément à la fin, plutôt que de tout rendre. Notez également que si vous ne récupérez des données qu'une seule fois, il peut être judicieux d'utiliser un composant "conteneur" qui récupère vos données et les transmet à votre composant "stupide" comme accessoire.

+0

Merci, c'est incroyable comment je pourrais manquer ça ... –

+1

'.map ((clé, valeur) => ...)' est faux. '.map ((clé, index) => ...)' est correct. Vous aurez besoin de 'const value = this.state.leaderboard [clé]' ou similaire. – ZephDavies