如何将React组件的状态重置为先前应用的状态?

时间:2018-05-05 16:37:22

标签: javascript reactjs

我有一个切换下拉菜单的按钮。在此菜单中,用户可以切换复选框,应用更改或取消。

取消应将复选框重置为之前应用的更改。

我正在努力重置FilterMenu组件的状态。我试图将初始状态字符串化,但事实证明这是有限的。

如何将FilterMenu组件的状态重置为先前应用的更改?

当用户取消时:

过滤组件

//close menu and reset state
handleCancel() {    
    this.setState({menuOpen: false});
    this.props.resetState();
}
调用

resetState来解析我的初始状态并设置它。

主要组件

resetState() {
   this.setState(JSON.parse(this.baseState));
}

const FilterMenu = ({checkBoxes, handleChange, handleCancel, handleSave}) => {
  return (
    <div>
      {Object.keys(checkBoxes).map(key => {
        return (
          <div key={key}>
            <label htmlFor={key}>{checkBoxes[key].name}</label>
            <input
              id={key}
              type="checkbox"
              checked={checkBoxes[key].isChecked}
              onChange={handleChange}
            />
          </div>
        );
      })}
      <button onClick={handleCancel}>Cancel</button>
      <button onClick={handleSave}>Save</button>
    </div>
  );
};

class Filter extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      menoOpen: false,
    };

    this.handleCancel = this.handleCancel.bind(this);
    this.handleButtonClick = this.handleButtonClick.bind(this);
  }

  handleCancel() {
    this.setState({menuOpen: false});
    this.props.resetState();
  }

  handleButtonClick() {
    this.setState({menuOpen: !this.state.menuOpen});
  }

  render() {
    return (
      <div>
        <button onClick={this.handleButtonClick}>Choose Fruits</button>
        {this.state.menuOpen && (
          <FilterMenu
            checkBoxes={this.props.checkBoxes}
            handleSave={this.props.handleSave}
            handleCancel={this.handleCancel}
            handleChange={this.props.handleChange}
          />
        )}
      </div>
    );
  }
}

//Parent component
class Main extends React.Component {
  constructor() {
    super();
    this.state = {
      checkBoxes: {
        1: {
          name: 'Apple',
          isChecked: true,
        },
        2: {
          name: 'Pear',
          isChecked: true,
        },
        3: {
          name: 'Tomato',
          isChecked: true,
        },
      },
      fruit: {
        1: {
          name: 'Apple',
        },

        3: {
          name: 'Apple',
        },
        4: {
          name: 'Pear',
        },
        5: {
          name: 'Tomato',
        },
        6: {
          name: 'Apple',
        },
      },

      checkedBoxes: [],
    };

    this.baseState = JSON.stringify(this.state);
    this.fruitFilter = this.fruitFilter.bind(this);
    this.handleSave = this.handleSave.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.resetState = this.resetState.bind(this);
  }

  resetState() {
    this.setState(JSON.parse(this.baseState));
  }

  //populates the checkedboxs array with name to filter by
  handleSave() {
    //look at the checked boxes
    //filter the fruit based on the ones that are checked`
    const checkedBoxes = Object.keys(this.state.checkBoxes)
      .filter(key => {
        //return name of fruit if it is checked
        return this.state.checkBoxes[key].isChecked
          ? this.state.checkBoxes[key].name
          : false;
      })
      .reduce((a, b) => {
        a.push(this.state.checkBoxes[b].name);
        return a;
      }, []);

    console.log(checkedBoxes);
    this.setState({checkedBoxes: checkedBoxes});
  }

  //handles the checkbox toggle
  handleChange(e) {
    const checkBoxes = {...this.state.checkBoxes};
    checkBoxes[e.target.id].isChecked = e.target.checked;
    this.setState({checkBoxes: checkBoxes});
  }

  //filteres the fruit - if nothing is checked return them all
  fruitFilter(fruit) {
    return Object.keys(fruit)
      .filter(key => {
        return (
          this.state.checkedBoxes.length <= 0 ||
          this.state.checkedBoxes.indexOf(fruit[key].name) > -1
        );
      })
      .reduce((a, b) => {
        a[b] = fruit[b];
        return a;
      }, {});
  }

  render() {
    const visibleFruits = this.fruitFilter(this.state.fruit);
    return (
      <div>
        <Filter
          resetState={this.resetState}
          checkBoxes={this.state.checkBoxes}
          handleSave={this.handleSave}
          handleChange={this.handleChange}
        />
        <div>
          <h2>Filtered Fruit</h2>
          {Object.keys(visibleFruits).map(key => {
            return (
              <div key={key}>
                <span>{visibleFruits[key].name}</span>
              </div>
            );
          })}
        </div>
      </div>
    );
  }
}

ReactDOM.render(<Main />, document.getElementById('react'))
<div id="react"></div>

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

1 个答案:

答案 0 :(得分:0)

问题是您在修改之前没有保存以前的状态。请记住,构造函数只被调用一次 我在handleSave

中添加的代码
this.baseState =  JSON.stringify(this.state.checkBoxes)

并在resetState

this.setState({checkBoxes: JSON.parse(this.baseState)});

以下是修改后的版本:

&#13;
&#13;
const FilterMenu = ({checkBoxes, handleChange, handleCancel, handleSave}) => {
  return (
    <div>
      {Object.keys(checkBoxes).map(key => {
        return (
          <div key={key}>
            <label htmlFor={key}>{checkBoxes[key].name}</label>
            <input
              id={key}
              type="checkbox"
              checked={checkBoxes[key].isChecked}
              onChange={handleChange}
            />
          </div>
        );
      })}
      <button onClick={handleCancel}>Cancel</button>
      <button onClick={handleSave}>Save</button>
    </div>
  );
};

class Filter extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      menoOpen: false,
    };

    this.handleCancel = this.handleCancel.bind(this);
    this.handleButtonClick = this.handleButtonClick.bind(this);
  }

  handleCancel() {
    // this.setState({menuOpen: false});
    this.props.resetState();
  }

  handleButtonClick() {
    this.setState({menuOpen: !this.state.menuOpen});
  }

  render() {
    return (
      <div>
        <button onClick={this.handleButtonClick}>Choose Fruits</button>
        {this.state.menuOpen && (
          <FilterMenu
            checkBoxes={this.props.checkBoxes}
            handleSave={this.props.handleSave}
            handleCancel={this.handleCancel}
            handleChange={this.props.handleChange}
          />
        )}
      </div>
    );
  }
}

//Parent component
class Main extends React.Component {
  constructor() {
    super();
    this.state = {
      checkBoxes: {
        1: {
          name: 'Apple',
          isChecked: true,
        },
        2: {
          name: 'Pear',
          isChecked: true,
        },
        3: {
          name: 'Tomato',
          isChecked: true,
        },
      },
      fruit: {
        1: {
          name: 'Apple',
        },

        3: {
          name: 'Apple',
        },
        4: {
          name: 'Pear',
        },
        5: {
          name: 'Tomato',
        },
        6: {
          name: 'Apple',
        },
      },

      checkedBoxes: ['Apple', 'Pear', 'Tomato'],
    };
    this.baseState =  JSON.stringify(this.state.checkBoxes)
    this.fruitFilter = this.fruitFilter.bind(this);
    this.handleSave = this.handleSave.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.resetState = this.resetState.bind(this);
  }

  resetState() {
    console.log(this.baseState)
    this.setState({checkBoxes: JSON.parse(this.baseState)});
  }

  //populates the checkedboxs array with name to filter by
  handleSave() {
    //look at the checked boxes
    //filter the fruit based on the ones that are checked`
    this.baseState =  JSON.stringify(this.state.checkBoxes)
    const checkedBoxes = Object.keys(this.state.checkBoxes)
      .filter(key => {
        //return name of fruit if it is checked
        return this.state.checkBoxes[key].isChecked
          ? this.state.checkBoxes[key].name
          : false;
      })
      .reduce((a, b) => {
        a.push(this.state.checkBoxes[b].name);
        return a;
      }, []);
    console.log(checkedBoxes);
    this.setState({checkedBoxes: checkedBoxes});
  }

  //handles the checkbox toggle
  handleChange(e) {
    const checkBoxes = {...this.state.checkBoxes};
    checkBoxes[e.target.id].isChecked = e.target.checked;
    
    this.setState({checkBoxes: checkBoxes});
  }

  //filteres the fruit - if nothing is checked return them all
  fruitFilter(fruit) {
    return Object.keys(fruit)
      .filter(key => {
        return (
          this.state.checkedBoxes.length <= 0 ||
          this.state.checkedBoxes.indexOf(fruit[key].name) > -1
        );
      })
      .reduce((a, b) => {
        a[b] = fruit[b];
        return a;
      }, {});
  }

  render() {
    const visibleFruits = this.fruitFilter(this.state.fruit);
    return (
      <div>
        <Filter
          resetState={this.resetState}
          checkBoxes={this.state.checkBoxes}
          handleSave={this.handleSave}
          handleChange={this.handleChange}
        />
        <div>
          <h2>Filtered Fruit</h2>
          {Object.keys(visibleFruits).map(key => {
            return (
              <div key={key}>
                <span>{visibleFruits[key].name}</span>
              </div>
            );
          })}
        </div>
      </div>
    );
  }
}

ReactDOM.render(<Main />, document.getElementById('react'))
&#13;
<div id="react"></div>

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

请注意,由于性能问题,不建议使用JSON.stringify克隆对象,对于实际应用程序,您应该使用正确的深度克隆方法(来自库或您自己的实现)