React - State Update value of only a specific key

I am trying to experiment with React, I have a problem updating status values ​​for a specific key.

Here is my condition

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 : { } } 

I call the external component and send parameters to it.

 <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)}/> 

Component in an external file:

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

When changing a value in a text box

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

While I try to change any field values, it sets the rest 2 with empty. For example, if I try to edit the Facebook text box, it will set the values ​​of Twitter and Instagram.

Can I find out what I am doing wrong in setting handleChange? I'm sure something is wrong with this.setState , but not sure how to target a specific key value.

+5
source share
3 answers

In this case, you need to get the previous state and create a new one (for merge states you can use Object.assign , the distribution operator ... or lodash merge ), because setState ,

Performs a fuzzy merge of nextState into its current state.

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

Example

 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> 
+8
source

setState does a shallow merge instead of a deep one (more explanation in docs ), so you completely overwrite all of connections with your only value. If you want to keep the rest of the keys in connections intact, you can change handleChange to this:

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

This will be a shallow copy of all this.state.connections , and then set e.target.name on top of it.

+3
source

You are right, the problem is in your setState.

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

A simple solution would be the following:

 handleChange(e) { this.setState({ connections : {[e.target.name]: e.target.value, twitter: 'initial val', instagram: 'initial val'} }) } 
+1
source

Source: https://habr.com/ru/post/1262102/


All Articles