javascript - React 中什么算作变异状态?

标签 javascript reactjs

背景位于顶部,我的实际问题很简单,位于底部,但我提供了上下文,以防我完全错误地解决这个问题,而我的问题甚至不相关。我只使用 React 大约两周。

我想做的是创建一个单一的、可重复使用的背景,可以通过单击它或单击使用背景的元素上的控件来关闭它。这是为了避免在 DOM 中的多个位置渲染多个背景(例如,将背景与每种不同类型的模式、侧边抽屉或内容预览分组)或拥有背景状态的多个真实来源。

我所做的是创建背景本身,但不会导出

const Backdrop = props => (
  props.show ? <div onClick={props.onClose} className={classes.Backdrop}></div> : null
);

我还创建了一个背景上下文,由 WithBackdrop 高阶类组件管理,该组件管理背景的状态并相应地更新上下文

class WithBackdrop extends Component {
  state = {
    show: true,
    closeListeners: []
  }

  show() {
    this.setState({ show: true });
  }

  hide() {
    this.state.closeListeners.map(f => f());
    this.setState({ show: false, closeListeners: [] });
  }

  registerCloseListener(cb) {
    // this.setState({ closeListeners: [...this.state.closeListeners, cb]});
    // Does this count as mutating state?
    this.state.closeListeners.push(cb);
  }

  render() {
    const contextData = {
      isShown: this.state.show,
      show: this.show.bind(this),
      hide: this.hide.bind(this),
      registerCloseListener: this.registerCloseListener.bind(this)
    };
    return (
      <BackdropContext.Provider value={contextData}>
        <Backdrop show={this.state.show} onClose={this.hide.bind(this)} />
        {this.props.children}
      </BackdropContext.Provider>
    );
  }
}

export default WithBackdrop;

我还导出了一个“backdropable”HOC,它用上下文消费者包装了一个组件

export const backdropable = Component => (props) => (
  <BackdropContext.Consumer>
    {value => <Component {...props} backdropContext={value}/>}
  </BackdropContext.Consumer>
);

此 API 的用法如下:包装布局/应用程序中您希望可能具有背景的部分,并向任何将激活背景的组件提供上下文。 “Backdropable”只是我用来表示“可以触发背景”的一个懒惰词(此处未显示,但我使用的是 TypeScript,这作为接口(interface)名称更有意义)。可背景组件可以调用 show() 或 hide(),而不必担心可能触发背景的其他组件,也不必担心有关背景状态的多个事实来源。

然而,我遇到的最后一个问题是如何触发可背景组件关闭处理程序?我决定 WithBackdrop HOC 将维护一个监听器列表,以便在通过单击背景(而不是通过可背景组件的关闭按钮或其他内容)关闭背景时需要使用react的组件。这是我用来测试的模态组件

const modal = (props) => {
  props.backdropContext.registerCloseListener(props.onClose);

  return (
    <div
    className={[
      classes.Modal,
      (props.show ? '' : classes.hidden)
    ].join(' ')}>
    {props.children}
    <button onClick={() => {
      props.onClose();
      props.backdropContext.hide()
    }}>Cancel</button>
    <button onClick={props.onContinue}>Continue</button>
  </div>
  )
} 

export default backdropable(modal);

据我了解,最好的做法是永远不要改变状态。我的问题是,推送到保持在状态中的数组是否算作变异状态,以及我应该从中期待什么潜在的不良后果?我是否应该每次都将数组复制到包含新元素的新数组中,或者如果我尝试更改状态成员的引用,我只会得到未定义的 React 行为。据我了解, react 仅浅层比较前一个和下一个状态以确定重新渲染并提供用于更复杂比较的实用程序,所以这应该没问题吧?原因是数组复制方法触发了重新渲染,然后模态尝试重新注册 closeListener,然后 WithBackdrop 尝试再次添加它......然后我得到了无限状态更新循环。

即使简单地推送到同一个数组没有任何问题,您认为有更好的方法吗?

谢谢,我真诚地感谢任何试图回答这个长问题的人所付出的努力。

编辑: this.setState({ closeListeners: [...this.state.closeListeners, cb]}); 导致无限状态更新循环。

最佳答案

React 中的改变状态是指在不使用 setState 的情况下更改状态中的任何值或引用对象。

As far as I understand, it is best practice to never mutate state. My question is, does pushing to an array maintained in state count as mutating state,

是的

and what potentially bad consequences should I expect from this?

您可能会更改状态值,但不会看到用户界面更新。

Should I copy the array into a new array with the new element every single time,

是的:

const things = [...this.state.things]
// change things
this.setState({ things })

or will I only get undefined React behaviour if I try to change the reference of a state member. As far as I understand react only shallowly compares previous and next state to determine re-renders and provides utilities for more complicated comparisons, and so this should be fine right?

如果您调用setState,它将进行比较,并在必要时进行更新。如果您不使用 setState,它甚至不会检查。

关于javascript - React 中什么算作变异状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61195742/

相关文章:

javascript - React Component 中的 render 没有返回任何内容

javascript - 如何将函数放在 return 之外,然后从 onChange react 中调用它?

reactjs - React-i18next addResourceBundle 不是一个函数

javascript - 在 React 中如何使用条件渲染?

javascript - Node.js 如何进行条件回调?

javascript - 减少由 ui-grid 或替代网格解决方案创建的监视

javascript - 仅当从 Http 服务获取数据时如何显示微调器?

javascript - 使用 jquery 验证插件验证登录并重定向到成功页面

javascript - 如何在 React 中动态地在一些现有元素之间添加新元素?

javascript - 使用ajax调用Action不显示页面