首页 > 解决方案 > 反应反模式?

问题描述

以下是 React 中的反模式吗?我喜欢这种模式,因为当组件被实例化时,它为我提供了静态函数的上下文。然后稍后我可以导入该类并调用静态方法来修改状态。或者这可以以更好的方式完成吗?

// componentA.js

function bleedContext() {
  ComponentA.staticMethod = ComponentA.staticMethod.bind(this)
}

export default class ComponentA {
  static staticMethod() {
    this.setState({foo: 'bar'})
  }
  
  constructor() {
    this.state = {}
    bleedContext.call(this)
  }
  
  render() {
    return (
      ...
    )
  }
}

// componentB.js

import ComponentA from 'path/to/componentA'

export default class ComponentB {  
  handleClick() {
    ComponentA.staticMethod()
  }
  
  render() {
    return (
      <button onClick={this.handleClick} />
    )
  }
}

标签: javascriptreactjsstatic

解决方案


这显然是一种反模式,也可能是一个错误,具体取决于条件。静态类方法不应与类实例一起操作。staticMethod绑定到特定的组件实例和用途setState,这只能证明一个类是单例(尽管单例通常也是反模式)。如果期望有多个类实例,这将导致错误和内存泄漏,并且每个 React 组件都应该有多个实例,至少在测试时是这样。

在 React 中,两个独立组件相互交互的正确方法是拥有一个提供这种交互的公共父组件,例如:

class ModalContainer extends Component {
  modalRef = React.createRef();

  render() {
    return <>
      <Modal ref={this.modalRef} />
      <SomeComponentThatUsesModal modalRef={this.modalRef} />
    </>;
  }
}

上面示例的问题是,如果是嵌套的,这将需要modalRef深入传递 prop 。<SomeComponentThatUsesModal>

这个问题可以通过 React 上下文或其他第三方全局状态解决方案(如 Redux)来解决。

这可以使用 React 16.3 上下文 API 来完成,考虑到Modal类实例具有open方法:

const ModalContext = React.createContext();

function getModal(modalRef) {
  return {
    open: data => modalRef.current.open(data);
    close: () => modalRef.current.close();
  }
}

class ModalContainer extends Component {
  modalRef = React.createRef();

  render() {
    return <>
      <Modal ref={this.modalRef} />
      <ModalContext.Provider value={getModal(this.modalRef)}>
        {this.props.children}
      </ModalContext.Provider>
    </>;
  }
}

然后对于任何深度嵌套的组件模态对象,使用open和 close 方法将通过上下文可用:

const SomeComponentThatUsesModal = props => <div>
  <ModalContext.Consumer>
    {modal => <button onClick={() => modal.open('foo')} />}
  </ModalContext.Consumer>
</div>;

<ModalContainer>
  ...deeply nested component
  <SomeComponentThatUsesModal />
  ...
</ModalContainer>

这是一个演示


推荐阅读