React router componentDidMount не выполняется после переключения маршрута

#reactjs #react-router

#reactjs #react-маршрутизатор

Вопрос:

Я создаю веб-приложение react, используя react-router для навигации между страницами. Некоторые из этих страниц зависят от componentDidMount, запускаемого при переходе на страницу. Однако, похоже, это не запускается, пока я не обновлю страницу, которая кажется пользователям очень нелогичной.

Есть ли способ принудительно запустить componentDidMount, возможно, после завершения метода визуализации.

Извините, если это рассматривается как дублирующий вопрос, но ничто из того, что я видел, не помогло мне понять, как решить эту проблему.

 componentDidMount = async () => {
    //initialize web3
    const web3 = await getWeb3();

    // get contract address
    const ethAddress = await storehash.options.address
    this.setState({ethAddress})

    //set account for Blockchain network
    this.setState({account: await web3.eth.getAccounts()})
    }
  

Комментарии:

1. Componentdidmount выполняется только один раз, при визуализации компонента. вы можете попробовать использовать другие жизненные циклы.

2. Также, если вы выполняете одну и ту же инициализацию для нескольких компонентов, вы могли бы переместить это в родительский и передать через props или переместить логику в компонент более высокого порядка

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

4. Я не отправляю никаких реквизитов на эту новую страницу, мне просто нужен способ запуска некоторого кода при загрузке этого нового маршрута

5. вы переходите по адресу, который соответствует одному и тому же Route , но имеет разные параметры, верно?

Ответ №1:

tl; dr — Только компоненты, отображаемые маршрутом (и их дочерние элементы), будут повторно отображаться при изменении маршрута.

Я собираюсь сделать несколько предположений. Во-первых, componentDidMount вы пытаетесь использовать компонент, который не является дочерним для одного из ваших компонентов маршрута.

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

componentDidMount Функция в компоненте, которая отображается с помощью маршрута, вероятно, там, где вам нужно быть. Однако, если вам нужно что-то обновить в состоянии этого компонента, когда монтируется один из его дочерних элементов, это не поможет. Однако вы можете сделать это несколькими различными способами.

Быстро и грязно Не берите в привычку делать это

Если вы просто что-то тестируете, быстрым и грязным методом является использование render свойства маршрута вместо component .

Так, например, если ваш маршрут выглядит следующим образом:

 <Route path="/some-route" component={NewComponent} />
  

Вы могли бы изменить это (опять же… только для быстрого тестирования, не рекомендуется использовать это в любом производственном коде!)

 <Route path="/some-route" render={(props) => {
    //do your console log or temporary testing stuff here
    return <NewComponent ...props />
}} />
  

Передайте функцию, которая передаст переменные от дочернего элемента

Менее грязным способом и предполагающим, что вы хотите, чтобы код имел доступ к чему-либо в этом родительском компоненте, было бы передать компоненту функцию. Опять же, вам пришлось бы использовать render для этого:

 someFunction = (passedVar) => {
    // do something with passedVar, which you'll pass from the new component
}

// ... then in the Router...

<Route path="/some-route" render={(props) => <NewComponent ...props onRouteLoaded={this.someFunction} />}} />
  

Тогда у вас была бы функция ( this.props.onRouteLoaded(...) ), которую вы могли бы запускать на componentDidMount из NewComponent , НО НЕ на этом родительском компоненте. Это позволит вам передавать переменные родительскому компоненту, если вам нужно получить доступ к состоянию этого компонента, реквизитам и т.д.

Рекомендуется, если вам нужно это сделать

Гораздо более чистым способом сделать это было бы использовать Redux state для передачи значений, но (со всем уважением) разберитесь с жизненными циклами React, прежде чем нарушать Redux (но вы ДОЛЖНЫ нарушить Redux!)

Ответ №2:

Вы можете использовать componentDidUpdate метод жизненного цикла для сравнения previous props с current props и повторного запуска логики снова; например

       constructor(props) {
          super(props);
          this.componentLogic = this.componentLogic.bind(this);
      }

      componentLogic() {
        // fetch something or some other business logic
      }
    
      componentDidMount() {
        this.componentLogic();
      }
    
      componentDidUpdate(prevProps) {
        // Typical usage (don't forget to compare props):
        if (
          this.props.reactRouterDom.params.slug !==
          prevProps.reactRouterDom.params.slug
        ) {
          this.componentLogic();
        }
      }   
  

Здесь я передаю route slug как prop через Higher Order Component(HOC) и отслеживаю изменение маршрута через componentDidUpdate жизненный цикл.