【问题标题】:React - State Update value only of Particular keyReact - 仅特定键的状态更新值
【发布时间】:2017-05-15 02:46:07
【问题描述】:

我正在尝试使用 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 有问题,但不确定如何定位特定的键值。

【问题讨论】:

  • 首先,您不应该拥有如此长的本地状态列表。原因 a)难以管理 2)如果您尝试更改任何内容,它将破坏您的代码。将大组件分解成较小的组件。对于您的问题,请尝试在 handleChange 函数中添加 e.preventDefault
  • @KhalidAzam 谢谢你让我知道,我看不出有什么办法可以打破这个名单,你有什么建议吗?因为,我的下一个组件是便利设施,它的列表是这个列表的 100 倍。我想存储为外部 js 并在此处导入。任何更好的想法将不胜感激。

标签: javascript reactjs ecmascript-6 react-redux


【解决方案1】:

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

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

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

例子

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>

【讨论】:

    【解决方案2】:

    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 设置在它上面。

    【讨论】:

    • 知道了,德鲁。感谢您的回答。
    【解决方案3】:

    你是对的,问题出在你的 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'}
        })
    }
    

    【讨论】:

      【解决方案4】:

      你实际上应该使用

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

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

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

      【讨论】:

      • 这个问题的正确答案
      猜你喜欢
      • 1970-01-01
      • 2020-03-02
      • 1970-01-01
      • 2017-05-08
      • 2021-06-18
      • 1970-01-01
      • 2020-04-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多