Я сейчас нахожусь на http://example.com/parentdir/module/2/

Этот URL фактически загружает класс Module.js, как указано в следующем маршруте:

<Route exact path={"/parentdir/module/:id"} component={Module} />

Он содержится в элементах <BrowserRouter> и <Switch>, как определено в моем файле index.js.

Класс Module имеет методы constructor и componentWillMount. Они устанавливают начальные детали и загружают информацию для записи № 2. Пока все отлично работает.

Теперь моя проблема состоит в том, что в компоненте внука Module.js я перенаправляю на другую страницу, такую как страница 3, со следующим перенаправлением:

return (
        <Redirect to="/parentdir/module/3/" />
)

Конструктор или componentWillMount не запускаются, поэтому запись № 3 загружается неправильно. Это потому, что этот компонент уже загружен в память с момента загрузки записи № 2? Каков наилучший способ перезагрузить Module.js, чтобы он правильно загружал запись № 3? Должен ли я как-то повторно инициализировать класс? Или мне как-то нужно передать данные из компонента внука обратно в класс модуля? Последний подход представляется утомительным.

Просто чтобы уточнить, перейду ли я непосредственно к http://example.com/parentdir/module/3 в адресной строке все работает правильно, но если я перенаправлю на этот же адрес в среде ReactJS, он не будет работать должным образом.

< Сильный > Обновление

Два ответа на мой вопрос уже даны. Одно решение предлагает использовать componentWillReceiveProps. Другое решение предлагает передать метод в качестве опоры ребенку, а затем внуку. Есть ли плюсы и минусы в использовании каждого из этих подходов или это просто вопрос предпочтений?

3
kojow7 25 Апр 2017 в 06:36

2 ответа

Лучший ответ

id передается как prop в форме this.props.params.id, поэтому вы должны использовать метод жизненного цикла componentWillReceiveProps, который запускается каждый раз при изменении props, что и является происходит в вашем случае.

Метод componentWillMount не будет работать при переходе от /parentdir/module/2 к /parentdir/module/3, так как компонент уже mounted. Он будет работать только при переходе от какого-либо другого компонента (например, при переходе напрямую).

В ваш Module компонент добавьте этот метод жизненного цикла

componentWillReceiveProps(nextProps){
      if(nextProps.params.id != this.props.params.id){
          //load information etc (whatever you are doing in componentWillMount)
       }
}

Происходит следующее: когда он получает более новый набор props, он сравнивает, изменился ли параметр id (все параметры маршрута находятся в объекте params в props) и когда он видит, что есть изменение, он выполняет логику. Сравнение на самом деле не нужно, и вы можете добавить логику, как в методе componentWillReceiveProps, но это было бы неэффективно, так как она вызывается каждый раз, когда изменяется объект props (может быть не id парам вообще).

2
mrinalmech 25 Апр 2017 в 04:06

componentWillMount () и componentDidMount () будут выполняться только один раз!

(Согласно жизненному циклу компонента React https: // facebook .github.io / реагирует / документы / реагирует - component.html # заместитель компонент - жизненный цикл )

Если вы хотите, чтобы ваш модуль обновлялся каждый раз, когда обновляется модуль внука, вам нужно создать функцию в своем модуле и передать ее как реквизиты дочернему, а также модули внука (в метод визуализации основного модуля)

Эта функция ( updateThisModule ) и ваш метод рендеринга будут выглядеть примерно так:

РЕДАКТИРОВАННАЯ ВЕРСИЯ НИЖЕ: (это просто демонстрация того, как вызвать функцию обратного вызова на родительском компоненте из многоуровневого дочернего компонента, мы можем фактически сделать все что угодно в этом обратном вызове)

import React from 'react';

class Module extends React.Component {

  constructor(props) {
    super(props);
    // ...
  }

  updateThisModule = () => {
    // We can do whatever we want here, either forceUpdate the component
    // or setState, which will also trigger this component to update itself
    // (using setState is more natural, though)
    // *** OPTION 1
    // this.forceUpdate();
    // *** OPTION 2
    // this.setState({
    //   someState: 'someValue',
    //   ..
    // });
    // *** ...
    // ...
  }

  render(){
    // ...
    <ChildModule updateParent={this.updateThisModule} />
    // ...
  }
}

Аналогично, сделайте то же самое в методе рендеринга вашего дочернего модуля (чтобы передать эту функцию еще на 1 уровень в модуль grandchild):

class ChildModule extends React.Component {
  ...
  render(){
    // ...
    <GrandChildModule updateGrandParent={this.props.updateParent} />
    // ...
  }
}

После этого в модуле Grand-Child нам нужен триггер, который вызывает модуль верхнего уровня, который нужно обновить, я предлагаю вам запустить его в функции componentDidUpdate (). Тогда модуль Grand-Child может выглядеть так:

class GrandChildModule extends React.Component {
  constructor(props) {
     super(props);
     // ...
  }

  componentDidUpdate() { 
    // this will be executed every time this grand-child-module updates itself
    // we will then trigger the update function upward to the parent's level first, then the grand-parent's level (which is your main Module)
    this.props.updateGrandParent(); 
  }

  render(){
    // ...
  }
}

Приведенный выше код написан на ES6, если вы пишете свой по-другому, не стесняйтесь размещать его здесь, тогда мы можем вместе изменить ваш код, чтобы он работал!

PS: передача функции как подпорки дочернему компоненту также является основной идеей чистых компонентов React. Однако, если ваша иерархия модулей слишком глубокая (со многими дочерними, внучатыми, правнуковыми и т. Д.), Вы можете рассмотреть возможность использования Flux или Redux

1
thinhvo0108 26 Апр 2017 в 01:18
43601156