web-dev-qa-db-fra.com

React - Valeur de l'état de santé uniquement de la clé

J'essaie d'expérimenter avec React. J'ai un problème de mise à jour des valeurs d'état d'une clé particulière.

Voici mon état

this.state = {
        connections : {
            facebook : "http://facebook.com",
            flickr : null,
            foursquare : null,
            googleplus : null,
            id : 0,
            instagram : "http://instagram.com/",
            openstreetmap : null,
            pinterest : null,
            place_id : 1,
            tomtom : null,
            tripadvisor : null,
            Twitter : "http://Twitter.com",
            vimeo : null,
            wikipedia : null,
            Yelp : null,
            youtube : null
        },
        contact : {

        }
    }

J'appelle un composant externe et lui envoie des paramètres.

<Connection type="Facebook" icon={facebookIcon} placeholder="Add Facebook Link" name="facebook" value={this.state.connections.facebook} onChange={this.handleChange.bind(this)}/>
<Connection type="Twitter" icon={twitterIcon} placeholder="Add Twitter Link" name="Twitter" value={this.state.connections.Twitter} onChange={this.handleChange.bind(this)}/>
<Connection type="Instagram" icon={instagramIcon} placeholder="Add Instagram Link" name="instagram" value={this.state.connections.instagram} onChange={this.handleChange.bind(this)}/>

Composant dans un fichier externe: 

<input type="text" name={this.props.name} placeholder={this.state.placeholder} value={this.props.value} onChange={this.props.onChange} />

Lors du changement de valeur dans la zone de texte,

handleChange(e) {        
    this.setState({
        connections : {[e.target.name]: e.target.value}
    })
}

Pendant que j'essaie de modifier les valeurs des champs, il définit le reste 2 avec vide. Par exemple, si j'essaie de modifier la zone de texte de Facebook, les valeurs Twitter et Instagram sont définies comme vides. 

Puis-je savoir ce que je fais mal en configurant handleChange? Je suis sûr que quelque chose ne va pas avec this.setState , mais je ne sais pas comment cibler une valeur de clé particulière.

7
Deepak Bandi

Dans ce cas, vous devez obtenir l'état précédent et créer un nouveau (pour les états de fusion, vous pouvez utiliser Object.assign, l'opérateur spread ... ou lodash merge), car setState ,

Effectue une fusion peu profonde de nextState dans l'état actuel. 

this.setState({    
  connections: Object.assign(
    {}, 
    this.state.connections,
    { [e.target.name]: e.target.value }
  ),
  contact: {}
});

Exemple

class Connection extends React.Component {
  render() {
    return <input 
      type="text"
      placeholder={this.props.placeholder}
      name={this.props.name}
      value={this.props.value} 
      onChange={this.props.onChange} />
  }
}

class App extends React.Component {
  constructor() {
    super();
    
    this.state = {
      connections : {
        facebook : "http://facebook.com",
        flickr : null,
        foursquare : null,
        googleplus : null,
        id : 0,
        instagram : "http://instagram.com/",
        openstreetmap : null,
        pinterest : null,
        place_id : 1,
        tomtom : null,
        tripadvisor : null,
        Twitter : "http://Twitter.com",
        vimeo : null,
        wikipedia : null,
        Yelp : null,
        youtube : null
      },
      contact: {}
    }
  }
  
  handleChange(e) {        
    
    
    this.setState({    
      connections: Object.assign(
        {}, 
        this.state.connections,
        { [e.target.name]: e.target.value }
      ),
      contact: {}
    })
  }
  
  render() {
    return (
      <div>
      
        <Connection 
          type="Facebook" 
          placeholder="Add Facebook Link"
          name="facebook" 
          value={this.state.connections.facebook}
          onChange={this.handleChange.bind(this)} 
        />
    
        <Connection 
          type="Twitter" 
          placeholder="Add Twitter Link" 
          name="Twitter" 
          value={this.state.connections.Twitter} 
          onChange={this.handleChange.bind(this)}
        />

        <Connection 
          type="Instagram"
          placeholder="Add Instagram Link"
          name="instagram" 
          value={this.state.connections.instagram}
          onChange={this.handleChange.bind(this)}
        />
      </div>
    );
  }
}


ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

9
Alexander T.

setState effectue une fusion peu profonde au lieu d'une fusion profonde (plus d'explications dans les docs ), de sorte que vous écrasez complètement connections avec votre seule valeur. Si vous souhaitez conserver les autres clés de connections intactes, vous pouvez remplacer handleChange par ceci:

handleChange(e) {        
    this.setState({
        connections : {...this.state.connections, [e.target.name]: e.target.value}
    })
}

Cela va copier superficiellement tout this.state.connections, et placer ensuite e.target.name dessus.

4
Drew Schuster

Vous avez raison, le problème vient de votre setState.

handleChange(e) {        
    this.setState({
        connections : {[e.target.name]: e.target.value} //this will trigger Twitter and instagram with empty value.
    })
}

Une solution de contournement simple serait:

handleChange(e) {        
    this.setState({
        connections : {[e.target.name]: e.target.value, Twitter: 'initial val', instagram: 'initial val'}
    })
}
1
Razvan Alex

Vous devriez plutôt utiliser plutôt

handleChange(e) {
  this.setState(oldState => ({
    connections: {[e.target.name]: e.target.value, ...oldState.connections},
  }));
}

sinon, vous pourriez écraser les modifications d’état qui n’ont pas encore été appliquées.

voir https://reactjs.org/docs/state-and-lifecycle.html

0
Wuwala Wala