即使在卸载组件后仍然检查React Checkbox

时间:2017-04-18 20:18:42

标签: javascript reactjs dom checkbox redux

所以,我有一个带复选框的项目列表,就像经典的待办事项应用程序一样。

enter image description here

当我选择" Johnny"然后单击,"删除所选记录,"约翰尼确实离开了。耶!

enter image description here

但是,一旦Johnny离开,现在就会检查Renee。

enter image description here

我没有点击Renee。我只点击了Johnny,但是一旦Johnny被删除,Renee就被检查了。跆拳道?

显然,正在发生的事情是复选框DOM保持被检查的状态,即使我刚刚清除了复选框。

我尝试通过更新componentWillUnmount中的状态来解决这个问题,但这没有用。

import React, {Component} from 'react';

class Person extends Component {

  constructor(props) {
    super(props);

    this.state = {
      checked: false
    }

    this.checkboxToggle = this.checkboxToggle.bind(this);
  }

  checkboxToggle() {
    this.setState({ checked: !this.state.checked }, () => {
      if (this.state.checked === false) {
        console.log("Checked should be FALSE");
      }
      else if (this.state.checked === true) {
        console.log("Checked should be TRUE");
        this.props.setForDelete(this.props.person._id);
      }
    });
  }

  componentWillUnmount() {
    this.setState({ checked: false });
  }

    render() {
        return (
          <div>
            <input type="checkbox" name="person" checked={this.state.checked} onChange={this.checkboxToggle} />
            {this.props.person.name} ({this.props.person.age})
          </div>
        );
    }
}

export default Person;

Person组件中的其他所有内容都正常工作。删除任何记录后,如何取消选中所有复选框?

更新:这是人员列表,包含所有人员的组件。

import React, { Component } from 'react';
import Person from './Person';

class PeopleList extends Component {

  constructor(props) {
    super(props);
  }

  componentWillUnmount() {
    this.props.resetSetForDeleteArr();
  }

  render() {
    return(
      <div>
        {this.props.people.map((person, i) => {
          return <Person key={i} person={person} setForDelete={this.props.setForDelete} />;
        })}
        <div onClick={() => this.props.deleteRecords()}>Delete Selected Records</div>
        <div onClick={() => this.props.resetSetForDeleteArr()}>Empty Array.</div>
      </div>
    );
  }

} // end class

export default PeopleList;

3 个答案:

答案 0 :(得分:6)

不要将数组索引用作关键属性!

密钥是React用于识别DOM元素的唯一支柱。如果密钥与以前相同,在您的情况下0 React假定DOM元素表示与以前相同的内容 - 即使现在还有另一个文本。

因此,React会重新呈现状态并更新已检查的属性。

使用独特的内容,例如:

<Person key={person + '_' + i} ...

答案 1 :(得分:3)

尝试更改PeopleList

中的以下行
{this.props.people.map((person, i) => {
      return <Person key={person._id} person={person} setForDelete={this.props.setForDelete} />;
    })}

答案 2 :(得分:3)

我认为你可能会遇到状态问题并传递功能。我创建了一个示例,它使用简单的map和filter函数来镜像当前实现,以模仿删除。如果我不得不猜测您可能无法跟踪检查和删除哪些数据,并且可能会缓存已检查的值。正如您在下面的代码中所看到的,这里有一些建议,您可以实现以使代码更容易:

  • 将Person保留为Dumb / Leaf组件,毕竟它只是渲染 你的复选框,不要试图保持检查状态。 (至少 通常你不需要它来删除卸载生命周期。)
  • 你可以使用context或者一个帮助你跟踪状态的库,mobx实现起来相当简单。
  • onClick={() => this.props.deleteRecords()}>可能看起来更像onClick={this.props.deleteRecords.bind(this)}>如果您不需要人员列表中的任何额外逻辑。

看看这里并尝试运行它:

import React, {Component} from 'react';
import {render} from 'react-dom';

const Person  = ({person, setForDelete}) => (
          <div>
            <input type="checkbox" name="person" checked={person.checked} onChange={setForDelete.bind(this, person)} />
            {person.name}
          </div>
);


class PeopleList extends Component {

  render() {

    return(
      <div>
       {this.props.people.map((person, i) => {
         return <Person key={i} person={person} setForDelete={this.props.setForDelete} />;
       })}
       <div onClick={this.props.deleteRecords}>Delete Selected Records</div>
     </div>
    );
  }

} // end class

class App extends React.Component {

  constructor(props) {
    super(props)
    this.state = {people:[{id:1, name:'Cesar', checked:false},{id:2, name:'Jose', checked:false},{id:3, name:'Marbel', checked:false}]}
  }

  deleteRecords() {
    const people = this.state.people.filter(p => !p.checked);

    this.setState({people});
 }

  setForDelete(person) {
    const checked = !person.checked;
    const people = this.state.people.map((p)=>{
      if(p.id === person.id)
        return {name:person.name, checked};
      return p;
    });

    this.setState({people});
  }

  render () {

    return <PeopleList people={this.state.people} deleteRecords={this.deleteRecords.bind(this)} setForDelete={this.setForDelete.bind(this)}/>;
  }
}

render(<App/>, document.getElementById('app'));