如何保持#34;只是隐藏"部件

时间:2016-05-24 22:55:52

标签: reactjs flux

通过my previous question我了解到React会自动保留子组件的状态,这就是its documentation says的原因:

  

什么不应该进入状态?

     

反应组件:根据底层道具和状态在render()中构建它们。

现在我的问题是如何为我们隐藏的组件做同样的事情?

考虑一个子组件,它在迭代中不会被显示,同时我们希望在将来恢复时保留其状态!

为了说明我的确切含义,我设计了一个案例场景来向您展示。在以下代码中,您可以添加有状态子组件。为每个组件提供了一个复选框,以便您可以标记它们。最后,第三个按钮将隐藏未标记的子组件。我正在寻找一种方法来恢复未标记组件的状态。

Executable code

class BlackBox extends React.Component
{
  constructor() {
    super();
    this.state = {
      checked: false,
      counter: 0,
    };
  }

  increment = () => {
    this.setState(Object.assign({}, this.state, { counter: this.state.counter+1 }));
  };

  switch = () => {
    this.setState(Object.assign({}, this.state, { checked: !this.state.checked }));
  };

  isChecked() {
      return this.state.checked;
  }

  render() {
    return (
      <span onClick={this.increment} title={this.props.id} style={{
        fontSize: '24pt',
        border: '1px solid black',
        margin: 10,
        padding: 10,
      }}>
        <input type="checkbox" onChange={this.switch} checked={this.state.checked} />
        {this.state.counter}
      </span>
    );
  }
}

class RedBox extends React.Component
{
  constructor() {
    super();
    this.state = {
      checked: false,
      counter: 0
    };
  }

  increment = () => {
    this.setState(Object.assign({}, this.state, { counter: this.state.counter+1 }));
  };

  switch = () => {
    this.setState(Object.assign({}, this.state, { checked: !this.state.checked }));
  };

  isChecked() {
      return this.state.checked;
  }

  render() {
    return (
      <span onClick={this.increment} title={this.props.id} style={{
        fontSize: '24pt',
        border: '1px solid red',
        margin: 10,
        padding: 10,
      }}>
        <input type="checkbox" onChange={this.switch} checked={this.state.checked} />
        {this.state.counter}
      </span>
    );
  }
}

class Parent extends React.Component {
    static blackCount = 0;
    static redCount = 0;
    state = {
      childCmps: [],
      showOnlyChecked: false,
    };
    constructor(props, context) {
      super(props, context);
    }

    addBlackBox = () => {
      this.setState(Object.assign({}, this.state, {
        childCmps: [...this.state.childCmps, { Component: BlackBox,  id: "black" + (++Parent.blackCount) }],
      }));
    };

    addRedBox = () => {
      this.setState(Object.assign({}, this.state, {
        childCmps: [...this.state.childCmps, { Component: RedBox, id: "red" + (++Parent.redCount) }],
      }));
    };

    showHide = () => {
      this.setState(Object.assign({}, this.state, {
        showOnlyChecked: !this.state.showOnlyChecked,
      }));
    };

    render() {
      let children = this.state.childCmps.map(child => <child.Component key={child.id} id={child.id} ref={child.id} />);
      return (
        <div>
          <button onClick={this.addBlackBox}>Add Black Box</button> 
          <button onClick={this.addRedBox}>Add Red Box</button>
          <button onClick={this.showHide}>Show / Hide Unchecked</button>
          <br /><br />
          {children.filter(box => !this.state.showOnlyChecked || this.refs[box.props.id].isChecked())}
        </div>
      );
    }
}

ReactDOM.render(
    <Parent />,
    document.getElementById("root")
);

2 个答案:

答案 0 :(得分:3)

答案简短:

没有解决方案只有优点而且没有缺点(在现实生活中和你的问题中) 你真的只有3个选择:

  1. 使用父状态并管理您的数据(在父组件和/或商店中)
  2. 使用子状态并隐藏您不需要的孩子(因此找到另一个动画解决方案)
  3. 使用子状态并接受未重新呈现的孩子的状态 -
  4. 您可能想要查看redux以使用商店。

    答案很长

    如果你想

    • 从DOM中删除子项(例如,使用ReactCSSTransitionGroup进行动画制作)
    • 并保持选中/取消选中&amp;反信息

    然后你不能把它保持在儿童状态。根据定义,State绑定到组件的生命周期。如果从DOM(= unmounted)中删除它,那么您将丢失所有状态信息。

    因此,如果您想保存此信息,则必须将此信息移至父组件的状态(显然对于每个孩子)。

    您可以找到working codepen here

    关于此代码的其他一些注意事项:

    • 您的孩子<...Box>组件现在变得纯粹=无状态组件
    • 子组件在父级上调用方法,以更新已检查状态或计数器增量。在这些方法中,他们传递自己的ID
    • 最好不要将整个组件存储在状态中,而只应存储决定组件的道具。
    • 因此新的父状态包含一个对象数组,每个对象都有相关的支持数据
    • 在父级渲染中:最好先过滤组件,然后再创建要渲染的组件数组
    • 在父级中,您需要新的方法(onCheck()onClick()),它们将从状态更新数组中的特定对象。需要一些特殊的摆弄以确保我们不会在这里直接改变状态。
    • 对于setState(),您不需要执行Object.assign()并再次传递所有状态。如果为对象提供仅更改的参数,则react将保持其他参数不变。

答案 1 :(得分:0)

而不是完全从DOM中移除组件(正如您在filter中所做的那样),只需隐藏它。将children.filter替换为以下内容:

  {children.map((box, idx) => {
      var show = !this.state.showOnlyChecked || this.refs[box.props.id].isChecked();
      return <span key={idx} style={{display: (show? 'inline-block': 'none')}}>{box}</span>;
  })}