Я сейчас нахожусь на 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. Другое решение предлагает передать метод в качестве опоры ребенку, а затем внуку. Есть ли плюсы и минусы в использовании каждого из этих подходов или это просто вопрос предпочтений?
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
парам вообще).
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
Похожие вопросы
Связанные вопросы
Новые вопросы
reactjs
React - это библиотека JavaScript для создания пользовательских интерфейсов. Он использует декларативную компонентную парадигму и стремится быть одновременно эффективным и гибким.