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.
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>
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.
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'}
})
}
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.