Реагировать на анти-паттерн? - PullRequest
0 голосов
/ 11 сентября 2018

Является ли следующий анти-паттерн в 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 Ответ

0 голосов
/ 11 сентября 2018

Это явно антипаттерн и, возможно, ошибка, в зависимости от условий.Статический метод класса не должен работать с экземпляром класса.staticMethod привязан к конкретному экземпляру компонента и использует setState, это может быть оправдано только тем, что класс является синглтоном (хотя синглтон также часто является антипаттерном).Это приведет к ошибкам и утечкам памяти, если ожидается более одного экземпляра класса, и каждый компонент React должен иметь более одного экземпляра, по крайней мере для тестирования.

Правильный способ взаимодействия двух независимых компонентов.друг с другом в React должен иметь общий родительский компонент, который обеспечивает это взаимодействие, например:

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

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

Проблема с примером выше состоит в том, что для этого потребуется глубоко передать modalRef prop, если <SomeComponentThatUsesModal>nested.

Эта проблема решается с помощью контекста React или других сторонних глобальных решений, таких как Redux.

Это можно сделать с помощью API контекста React 16.3, учитывая, что экземпляр класса Modal имеетopen method:

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>

Вот демо .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...