2016-03-01 2 views
4

Disons que j'ai une classe avec un tableau de niveau d'étatReact: tableau de liaison aux champs dynamiquement ajouté

ElementsClass = React.createClass({ 
    getInitialState: function() { 
     return { 
      elements: [] 
     } 
    }, 
    addElement: function() { 
     var element = { 
      name: "" 
     }; 
    }, 
    render() { 
     return (
      {this.state.elements.map(function (element, i) { 
        return <input value={element.name} /> 
       } 
      )} 
     ) 
} 

L'idée étant que je peux ajouter dynamiquement au tableau des éléments et un nouveau champ de saisie apparaît.

Comment lier les données afin que je puisse changer la valeur dans le champ de saisie et que cela reflète automatiquement dans l'élément correct dans le tableau d'éléments?

Répondre

2

Pour synchroniser dynamiquement vos entrées avec votre tableau d'état, vous pouvez utiliser le package linkState du package react-catalyst. Une fois que vous avez installé avec NPM vous pouvez l'utiliser de la manière suivante:

//need to import 
import Catalyst from 'react-catalyst'; 

ElementsClass = React.createClass({ 
    // mixin the linkedstate component 
    mixins : [Catalyst.LinkedStateMixin],  

    getInitialState: function() { 
     return { 
      elements: [] 
     } 
    }, 
    addElement: function() { 
     var element = { 
      name: "" 
     }; 

     //add to elements array 
     this.state.elements.push(element); 

     //let react know to rerender necessary parts 
     this.setState({ 
      elements : this.state.elements 
     }); 
    }, 
    render() { 
     return (
      {this.state.elements.map(function (element, i) { 
        //use the linkState method 
        return <input valueLink={this.linkState('elements.'+i+'.name')} /> 
       } 
      )} 
     ) 
} 

La raison pour laquelle nous avons besoin du paquet react-catalyst est que uniquement Réagissons nativement valueLink lier des éléments d'état de niveau supérieur, dans votre cas elements. Évidemment, ce n'est pas particulièrement utile, mais heureusement, c'est un problème assez facile à résoudre.

Remarque: pour les éléments itérés comme les entrées d'élément, vous devez fournir une clé unique. Quelque chose comme ce qui suit (pourrait avoir besoin en train de modifier pour être plus précis):

{this.state.elements.map(function (element, i) { 
     //use the linkState method 
     return <input valueLink={this.linkState('elements.'+i+'.name')} key={'elinput' + i} /> 
    } 
)} 

Cela n'a pas d'effet vers l'extérieur sur votre application, il est surtout pour aider l'élément cible réagir en interne.

+0

Désolé, je ne pense pas que je clarifié la question complètement. Lorsque vous ajoutez 'value = {element.name}' dans le champ de saisie, le champ de saisie ne peut pas être modifié. Comment puis-je ajouter une méthode onChange qui cible correctement l'entrée pertinente dans le tableau des éléments – Pram

+0

@Pram ah, j'ai complètement mal compris. C'est en fait un peu plus compliqué. Vous devez utiliser 'valueLink' au lieu de' value' * mais * React ne le permet que pour les valeurs d'état de niveau supérieur. Je mettrai à jour ma réponse, mais vous aurez besoin d'une bibliothèque comme 'react-catalyst' pour faire la liaison bidirectionnelle de cette façon. –

+0

@Pram s'il vous plaît voir ma réponse mise à jour –

0

Si vous voulez faire avec juste ES5 et React, une solution serait:

var ElementsClass = React.createClass({ 

getInitialState: function() { 
    return { 
     elements: [] 
    } 
}, 
createElement: function(){ 
    var element = { 
    name: '' 
    }; 
    this.setState({elements: this.state.elements.concat(element)}); 
}, 
updateElement: function(pos, event) { 
    var value = event.target.value; 
    var updatedElements = this.state.elements.map(function(element, i){ 
     if (i === pos){ 
     return {name: value}; 
     } 
     return element; 
    }); 
    this.setState({elements: updatedElements}); 
}, 
render: function() { 
    console.log(this.state.elements); 
    return (
     <div> 
     {this.state.elements.map(function (element, i) { 
      var boundClick = this.updateElement.bind(this, i); 
      return <input key={i} onKeyUp={boundClick}/> 
     }.bind(this))} 
     <button onClick={this.createElement}>Add Element</button> 
     </div> 
    ) 
} 
}); 

React.render(<ElementsClass />, document.getElementById('app')); 

Vous voulez traiter l'état du composant comme immuable, de sorte que vous ne voulez pas appeler une méthode mutationniste comme pousser sur les éléments.

0

Ces situations sont gérées facilement avec des paquets de liens personnalisés.

State and Forms in React, Part 3: Handling the Complex State

import Link from 'valuelink'; 

// linked inputs will be deprecated, thus we need to use custom wrappers 
import { Input } from 'valueLink/tags.jsx' 

const ElementsClass = React.createClass({ 
    getInitialState: function() { 
     return { 
      elements: [] 
     } 
    }, 

    render() { 
     // Take link to the element 
     const elementsLink = Link.state(this, 'elements'); 

     return (
      <div> 
       { elementsLink.map((elementLink, i) => (
        <Input key={ i } valueLink={ elementLink.at('name') } /> 
       ))} 

       <button onClick={ elementsLink.push({ name : '' })}> 
        Add Elements 
       </button> 
      </div> 
     ); 
    } 
});