React - 仅对特定键的状态更新值

时间:2016-12-30 20:32:19

标签: javascript reactjs ecmascript-6 react-redux

我尝试使用React进行实验,我遇到了更新特定密钥的状态值的问题。

这是我的州

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

        }
    }

我正在调用外部组件并向其发送参数。

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

外部文件中的组件:

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

关于文本框中值的更改,

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

当我尝试更改任何字段值时,它会将其余2设置为空。例如,如果我尝试编辑Facebook的文本框,它会将Twitter和Instagram值设置为空。

我可以知道在设置handleChange时我做错了什么吗?我确定 this.setState 有问题,但不确定如何定位特定键值。

4 个答案:

答案 0 :(得分:10)

在这种情况下,您需要获取以前的状态并创建新的(对于合并状态,您可以使用Object.assign,传播运算符...或lodash merge ,因为setState

  

执行nextState到当前状态的浅层合并。

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

实施例

&#13;
&#13;
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'));
&#13;
<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>
&#13;
&#13;
&#13;

答案 1 :(得分:4)

setState执行浅合并而不是深度合并(the docs中的更多解释),因此您只需使用一个值完全覆盖所有connections。如果您希望connections中的其他密钥保持不变,可以将handleChange更改为:

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

这将对所有this.state.connections进行浅层复制,然后将e.target.name设置在其上方。

答案 2 :(得分:1)

你是对的,问题在于你的setState。

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

一个简单的解决方法是:

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

答案 3 :(得分:0)

您实际上应该宁愿使用

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

因为否则您可能会覆盖尚未应用的状态更改。

请参阅https://reactjs.org/docs/state-and-lifecycle.html