react反模式?

IT技术 javascript reactjs static
2021-04-10 15:03:55

以下是 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} />
    )
  }
}

1个回答

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

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

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

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

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

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

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

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>
    </>;
  }
}

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

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

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

这是一个演示

我更新了答案。希望这可以帮助。考虑在问题中提供有关您的案例的相关信息(A 是模态,B 是模态消费者),这将有助于其他读者理解案例。
2021-06-08 15:03:55
有趣的是,我以前没有使用过装饰器。你能解释一下代码吗?在您的示例中,我看不到 ComponentB 如何更新 ComponentA 的状态。
2021-06-10 15:03:55
谢谢澄清。我怀疑有更好的解决方案。我知道我在做的事情很糟糕,尤其是因为人们必须了解“单例”概念,否则它会崩溃。
2021-06-19 15:03:55