React Warning: Невозможно обновить компонент внутри тела функции другого компонента. - PullRequest
3 голосов
/ 04 марта 2020

Я использую Redux с компонентами класса в React. Имея два следующих состояния в хранилище Redux.

{ spinner: false, refresh: false }

В родительских компонентах у меня есть функция отправки для изменения этих состояний.

class App extends React.Component {
  reloadHandler = () => {
    console.log("[App] reloadComponent");

    this.props.onShowSpinner();
    this.props.onRefresh();
  };

  render() {
    return <Child reloadApp={this.reloadHandler} />;
  }
}

В дочернем компоненте я пытаюсь перезагрузить родительский компонент, как показано ниже.

class Child extends React.Component {
  static getDerivedStateFromProps(props, state) {
    if (somecondition) {
      // doing some redux store update
      props.reloadApp();
    }
  }

  render() {
    return <button />;
  }
}

Я получаю сообщение об ошибке, как показано ниже.

Предупреждение: невозможно обновить компонент внутри тела функции другого компонента.

Как убрать это предупреждение? Что я тут не так делаю?

Ответы [ 4 ]

6 голосов
/ 04 марта 2020

Похоже, у вас последняя сборка React@16.13.x. Вы можете найти более подробную информацию об этом здесь . Указано, что вы не должны setState другого компонента из другого компонента.

из документов:

Поддерживается вызов setState во время рендеринга, но только для того же компонента. Если вы вызовите setState во время рендеринга для другого компонента, теперь вы увидите предупреждение:
Warning: Cannot update a component from inside the function body of a different component.
Это предупреждение поможет вам найти ошибки приложения, вызванные непреднамеренными изменениями состояния. В редком случае, когда вы намеренно хотите изменить состояние другого компонента в результате рендеринга, вы можете заключить вызов setState в useEffect.


Переход к фактическому вопрос.

Я думаю, что нет необходимости в getDerivedStateFromProps в теле дочернего компонента. Если вы хотите вызвать связанное событие. Затем вы можете вызвать его через onClick дочернего компонента, так как я вижу, что это <button/>.

class Child extends React.Component {
  constructor(props){
    super(props);
    this.updateState = this.updateState.bind(this);
  }
  updateState() { // call this onClick to trigger the update
    if (somecondition) {
      // doing some redux store update
      this.props.reloadApp();
    }
  }

  render() {
    return <button onClick={this.updateState} />;
  }
}
4 голосов
/ 16 марта 2020

Для меня я отправлял в свой магазин редуксов в React Hook. Мне пришлось отправить в useEffect для правильной синхронизации c с циклом рендеринга React:

export const useOrderbookSubscription = marketId => {
  const { data, error, loading } = useSubscription(ORDERBOOK_SUBSCRIPTION, {
    variables: {
      marketId,
    },
  })

  const formattedData = useMemo(() => {
    // DISPATCHING HERE CAUSED THE WARNING
  }, [data])

  // DISPATCHING HERE CAUSED THE WARNING TOO

  // Note: Dispatching to the store has to be done in a useEffect so that React
  // can sync the update with the render cycle otherwise it causes the message:
  // `Warning: Cannot update a component from inside the function body of a different component.`
  useEffect(() => {
    orderbookStore.dispatch(setOrderbookData(formattedData))
  }, [formattedData])

  return { data: formattedData, error, loading }
}
0 голосов
/ 05 марта 2020

Я также решаю эту проблему из функционального компонента с помощью React 16.13. Я использую в своем компоненте Select (от Ant Design). Варианты являются детьми выбора. Итак, у меня есть эта иерархия (и ссылка на изолированную программную среду кода ниже):

  1. Мой компонент-обертка, который является родительским для дочернего компонента. Выберите компонент
  2. первый дочерний компонент: выберите
  3. Компоненты опций как дочерние компоненты компонента Select

Я определяю свою функцию useState () в (1), вызываю setFilteredList (setState) в (2), но элемент управления предназначен для обновления опций ( 3). Однако из того, что я прочитал, я должен иметь возможность вызывать мое установленное состояние из обработчика событий, так как он не работает при рендеринге. Буду признателен за любую помощь здесь!

Кодсэндбокс Ссылка: https://codesandbox.io/s/silly-pike-zwvpb?fontsize=14&hidenavigation=1&theme=dark

0 голосов
/ 05 марта 2020

Если вы хотите вызвать некоторую функцию, автоматически переданную в качестве реквизита от дочернего компонента, тогда лучше всего использовать методы жизненного цикла componentDidMount в случае компонентов класса или перехватчики useEffect в случае функциональных компонентов, поскольку в этот момент компонент полностью создан и также смонтирован.

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