首页 > 解决方案 > React 中的状态应该提升多高?

问题描述

中间组件应该控制状态的一部分并调用传递给它们的道具还是应该将状态提升到更高的位置?我一直在来回考虑是让子组件利用本地状态还是让更高的组件处理它并向下传递额外的道具。

在这个有限的例子中,我有一个Main组件。我在这个组件中显示一些数据并传递函数来过滤数据到子组件。但是,主要组件不一定需要知道menuOpen属性何时更改。但是,我需要在、和被调用menuOpen时更新。handleCancel()handleSave()handleButtonClick()

handleCancel()并且handleSave()都修改了显示的数据,因此我在Main组件中声明了它们。

我应该propsMain组件传递所有这些,还是使用中间组件来处理较小部分的本地状态,但也要props从父(祖父等)组件调用?

主要部件

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

    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() {
    this.setState({checkBoxes: JSON.parse(this.baseState)});
  }

  //populates the checkedboxs array with name to filter by
  handleSave() {
    const checkedBoxes = Object.keys(this.state.checkBoxes)
      .filter(key => {
        //....some logic 
      });

    this.baseState = JSON.stringify(this.state.checkBoxes);
    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 => {
        //...filter logic 
      })
  }

  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 (
              //... renders list of fruit
            );
          })}
        </div>
      </div>
    );
  }
}

子组件

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

    this.state = {
      menoOpen: false,
    };

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

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

  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.handleSave}
            handleCancel={this.handleCancel}
            handleChange={this.props.handleChange}
          />
        )}
      </div>
    );
  }
}

孙子组件

const FilterMenu = ({checkBoxes, handleChange, handleCancel, handleSave}) => {
  return (
    <div>
      {Object.keys(checkBoxes).map(key => {
        return (
          //... renders dropdown menu
        );
      })}
      <button onClick={handleCancel}>Cancel</button>
      <button onClick={handleSave}>Save</button>
    </div>
  );
};

标签: javascriptreactjs

解决方案


改进关注点的分离,我想你会更喜欢它。

  • 在 中定义所有复选框事件处理程序Filter
  • Filter仅与Main通过状态通信。
    • 不要强制Main评估 UI 组件以设置状态。
    • 根据需要定义要使用的Main状态Filter以避免上述情况。
  • Filter将构建复选框。
  • CancelSave按钮对我来说似乎是Filter关卡功能。
  • 一个FilterMenu组件现在看起来毫无意义,因为它什么都不Filter也许在更大的架构中它是有用的,但你总是可以在需要时重新考虑它
  • Filter组件是代码中将动作与状态分开的接缝。
    • 状态并没有被不必要地进一步推低。
    • 实际功能不会不必要地进一步提升。
    • Main和之间的耦合Filter减少了。Filter具有更大的重用潜力。

推荐阅读