【问题标题】:SetState overwrites previous state even with spread operator React.JS即使使用扩展运算符 React.JS,SetState 也会覆盖先前的状态
【发布时间】:2021-01-14 23:49:26
【问题描述】:

我在handleChange 中遇到了setState 的问题。 因此,在代码中单击addList 后,将出现divinputbutton,然后当我在input 内输入时,input state 将更新,单击添加按钮后div 将消失。 所以我的问题是下次单击addList 时,先前输入的值仍然存在并且hideAddList handler 没有将input 状态设置为空,并且当我输入新打开的div 之前的@987654334 时@ 将覆盖。即使使用索引和扩展运算符,它仍然存在同样的问题。

我该怎么办?

export class myClass extends Component {
    constructor(props) {
        super(props);
        this.state = {
            input: [{ title: '' }]

        };
        this.addList = this.addList.bind(this);
        this.hideAddList = this.hideAddList.bind(this);
        this.titleHandleChange = this.titleHandleChange.bind(this);
        

    }
    
    addList() {
       var x = document.getElementById("btn-list")
       var y = document.getElementById("add-button")
       x.style.display = 'none'
       y.style.display = ''
    }

    hideAddList() {
        var x = document.getElementById("btn-list")
        var y = document.getElementById("add-button")
        x.style.display = ''
        y.style.display = 'none';
        this.setState(prevState => ({ input: [...prevState.input, {title:''}]}))  
    }
     HandleChange(e, index){
       const { name, value } = e.target;
       const list = [...this.state.input];
       list[index][name] = value;
       this.setState({ input: list});
    }
    
   render() {
        return (
          <div>
          <button id="btn-list" className="btn btn-default btn-list" type="submit" onClick={this.addList}>Add Another List</button>
                        {this.state.input.map((x, i) => {
                                return (
                                    <div key={i} id="add-button" className="add-button" style={{ display: "none" }}>
                                        <input id="input" type="text" onChange={(e) => {this.HandleChange(e, i)}} value={x.title} name="title" className="form-control add-input" />
                                        <button className="btn btn-default btn-list-add" onClick={this.hideAddList} type="submit">Add</button>
                                    </div>
                                    )})}
          </div>
        )
     }
        
}

export default myClass

【问题讨论】:

    标签: javascript html reactjs


    【解决方案1】:

    根据您提供的代码,每次调用addList 时,您总是会得到第一个“添加按钮”元素,因为您的所有列表项都具有相同的 id。

    {this.state.input.map((x, i) => {
    ...
     <div key={i} id="add-button" ...> // here! they got the same id!
    

    所以这里发生的事情是您实际上一直在编辑第一个项目。您将需要为您的元素添加不同的 id。而AddList 应该得到最后一个项目的索引。

    例如:

    AddList()
    ...
    {this.state.input.map((x, i) => {
                return (
                   <div key={i} id={`add-button-${i}`} .... // here! add unique id for each item!
    

    整个代码应该是这样的:

    export default class myClass extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          input: [{title: ''}],
        };
        this.addList = this.addList.bind(this);
        this.hideAddList = this.hideAddList.bind(this);
        this.titleHandleChange = this.titleHandleChange.bind(this);
      }
    
      addList() {
        var lastItemIndex = this.state.input.length - 1; // you need to get the last item's index to make sure that you display the latest item
        var x = document.getElementById('btn-list');
        var y = document.getElementById(`add-button-${lastItemIndex}`);
        x.style.display = 'none';
        y.style.display = '';
      }
    
      hideAddList(i) {
        var x = document.getElementById('btn-list');
        var y = document.getElementById(`add-button-${i}`);
        x.style.display = '';
        y.style.display = 'none';
        this.setState(prevState => ({input: [...prevState.input, {title: ''}]}));
      }
      titleHandleChange(e, index) {
        const {name, value} = e.target;
        const list = [...this.state.input];
        list[index][name] = value;
        this.setState({input: list});
      }
    
      render() {
        return (
          <div>
            <button
              id="btn-list"
              className="btn btn-default btn-list"
              type="submit"
              onClick={this.addList}>
              Add Another List
            </button>
            {this.state.input.map((x, i) => {
              return (
                <div
                  key={i}
                  id={`add-button-${i}`}
                  className="add-button"
                  style={{display: 'none'}}>
                  <input
                    id="input"
                    type="text"
                    onChange={e => {
                      this.titleHandleChange(e, i);
                    }}
                    value={x.title}
                    name="title"
                    className="form-control add-input"
                  />
                  <button
                    className="btn btn-default btn-list-add"
                    onClick={() => this.hideAddList(i)}
                    type="submit">
                    Add
                  </button>
                </div>
              );
            })}
          </div>
        );
      }
    }
    

    为了调试,也许您可​​以尝试在titleHandleChange 中注销索引,这样您就可以找出您实际正在编辑的项目。

    ps,你可以写export default class MyClass extends ...,这样你就不需要在文件末尾再写export default MyClass了。

    【讨论】:

    • 感谢您的帮助和您的完整指南 :)
    【解决方案2】:

    状态已正确更改。你可以添加一个控制台日志来查看它:

    render() {
        console.log(this.state);
        return (
        ...
    

    它没有显示在您的屏幕上的原因是您为 id 'add-button' 设置的{display: 'none'} 。您的 var y = document.getElementById("add-button") 只会获得第一个元素,而不是整个元素列表。

    仅供参考,在您的案例的反应项目中使用document.getElementById 是不正确的。应该由国家来做。这是一个完整的例子:

    export class MyClass extends Component {
      constructor(props) {
        super(props);
        this.state = {
          input: [{title: ''}],
          showAnotherListBtn: true,
          showList: false,
        };
      }
    
      onClickAnotherListBtn = () => {
        this.setState({
          showAnotherListBtn: false,
          showList: true,
        });
      }
    
      addList = () => {
        this.setState({
          input: [...this.state.input, {title: ''}],
        });
      }
    
      handleChange(e, index) {
        const {name, value} = e.target;
        const list = [...this.state.input];
        list[index][name] = value;
        this.setState({input: list});
      }
    
      render() {
        console.log(this.state);
        return (
          <div>
            {this.state.showAnotherListBtn ?
              <button id="btn-list" className="btn btn-default btn-list" type="submit" onClick={this.onClickAnotherListBtn}>Add Another
                List</button> : null}
            {this.state.showList && this.state.input.map((x, i) => {
              return (
                <div key={i} id="add-button" className="add-button">
                  <input id="input" type="text" onChange={(e) => {
                    this.handleChange(e, i)
                  }} value={x.title} name="title" className="form-control add-input"/>
                  <button className="btn btn-default btn-list-add" onClick={this.addList} type="submit">Add</button>
                </div>
              )
            })}
          </div>
        )
      }
    }
    
    export default MyClass
    

    从上面的代码中可以看出,您只需使用布尔状态来确定是否应该显示该元素。

    希望这会有所帮助;)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-09
      • 1970-01-01
      • 2020-01-30
      • 2021-09-12
      • 1970-01-01
      • 2018-05-17
      • 2020-01-15
      • 1970-01-01
      相关资源
      最近更新 更多