在重定向到具有不同特性的同一页面时,React Router触发触发器重新加载/重新安装组件

时间:2019-04-15 09:54:27

标签: javascript reactjs lifecycle react-router-dom

我有一个演示应用程序,该应用程序使用 React(v.16.8.6) HashRouter 使用哈希路由器的要求)。我的应用程序仅获取一些天气数据,并显示某些城市天气的相关组件。

问题在于索引页面中有搜索功能,搜索页面上也有类似功能。给出搜索字词后,应用会重定向到#/search/{term}路由。一切都按预期工作,但是当我已经在搜索页面上并触发新搜索时,我重定向到具有不同{term}子弹(需要更新浏览器当前URL(包括哈希)的同一个搜索页面)。

由于未重新加载结果页面且未重新安装组件,因此不会触发生命周期挂钩(尤其是进行设置的componentDidMount)。

我做了一个变通办法来模拟组件的重新加载,但这有点像破解(例如,直接操作状态和设置超时,请参见下面的相关代码)。

在正确重新加载/重新安装组件时,是否有更好的方法来实现重定向到同一页面(并更改浏览器URL(包括哈希))?

App.js

import React, { Component } from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom';

import HomePage from './home';
import SearchPage from './search';
import WeatherPage from './weather';

import './App.css';

class App extends Component {
  render() {
    return (
    <HashRouter basename="/" hashType="slash">
    <Switch>
        <Route exact path={'/'} component={HomePage}></Route>
        <Route path={'/weather/:woeid'} component={WeatherPage}></Route>
        <Route path={'/search/:term'} component={SearchPage}></Route>
    </Switch>
    </HashRouter>
    );
  }
}

export default App;

SearchPage.js组件

import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import Weather from '../components/Weather';

function fetchData( term ) {
    return fetch('{api_url_here}?keyword='+term)
    .then(response => response.json());
}

class SearchPage extends Component {
  constructor(props){
      super(props);
      this.state = {
          loading: true,
          text: this.props.match.params.term,
          redirect: false,
          data: null
      };
  }

  componentDidMount() {
    fetchData(this.props.match.params.term).then(jsonResponse => {
        this.setState({
            loading: false,
            data: jsonResponse
        });
    });
  }

  handleOnClick = () => {
    this.setState({redirect: true});
  }

  handleInput = (evt) => {
    this.setState({text: evt.target.value});
  }

  render() {
    // any way to avoid this workaround while redirecting to same page?
    // [from here]
     if (this.state.redirect) {
        this.state.redirect = false;
        this.state.text = this.state.text.toLowerCase();
        this.state.data = null;
        this.state.loading = true;
        // simulate componentDidMount, since it os not re-called on same page
        setTimeout(()=>(fetchData(this.state.text).then(jsonResponse => {
            this.setState({
                loading: false,
                data: jsonResponse
            });
        })), 40);
        // redirect and update url
        return <Redirect to={"/search/"+this.state.text} />;
       // [to here]
  }
    return (
      <div>
      <h1>Search Page</h1>
      <div>
      <input type="text" placeholder="search.." value={this.state.text} onChange={this.handleInput} />
      <button type="button" onClick={this.handleOnClick}>Search!</button>
      </div>
      {this.state.loading ? 'Loading..' : (this.state.data && this.state.data.length ? this.state.data.map(res => (<Weather woeid={res.woeid} city={res.title} />)) : 'No results found!')}
      </div>
    );
  }
}

export default SearchPage;

基于重定向的解决方案(将重新加载/重新安装组件)(Tholle's answer

应用更改为以下内容:

class App extends Component {
  render() {
    return (
    <HashRouter basename="/" hashType="slash">
    <Switch>
        <Route exact path={'/'} component={HomePage}></Route>
        <Route path={'/weather/:woeid'} component={WeatherPage}></Route>
        <Route path={'/search/:term'} render={props => <SearchPage key={props.match.params.term.toLowerCase()} {...props} />}></Route>
    </Switch>
    </HashRouter>
    );
  }
}

SearchPage 更改为以下内容:

class SearchPage extends Component {
  constructor(props){
      super(props);
      this.state = {
          loading: true,
          text: this.props.match.params.term,
          redirect: false,
          data: null
      };
  }

  componentDidMount() {
    fetchData(this.props.match.params.term).then(jsonResponse => {
        this.setState({
            loading: false,
            data: jsonResponse
        });
    });
  }

  handleOnClick = () => {
    this.setState({redirect: true});
  }

  handleInput = (evt) => {
    this.setState({text: evt.target.value});
  }

  render() {
    if (this.state.redirect) {
        // redirect and update url
        return <Redirect to={"/search/"+this.state.text.toLowerCase()} />;
  }
    return (
      <div>
      <h1>Search Page</h1>
      <div>
      <input type="text" placeholder="search.." value={this.state.text} onChange={this.handleInput} />
      <button type="button" onClick={this.handleOnClick}>Search!</button>
      </div>
      {this.state.loading ? 'Loading..' : (this.state.data && this.state.data.length ? this.state.data.map(res => (<Weather woeid={res.woeid} city={res.title} />)) : 'No results found!')}
      </div>
    );
  }
}

2 个答案:

答案 0 :(得分:1)

一种解决方法是在componentDidUpdate组件中添加一个SearchPage生命周期挂钩,并检查term参数是否更改,然后再次执行搜索。

如果您想在term参数更改时重新安装组件,则可以使用key道具来卸载先前的组件,并在key更改时安装新的组件。

<Route
  path={"/search/:term"}
  render={props => <SearchPage key={props.match.params.term} {...props} />}
/>

答案 1 :(得分:1)

使用Link中的react-router-dom而不是<button>来更改路由,而不仅仅是重定向。然后在<Link>组件的onClick中调用fetchData并相应地设置状态。

<Link className="btn" to={"/search/"+this.state.text} onClick={this.handleOnClick}>Search!</Link>

然后在handleOnClick函数中

handleOnClick() {
   this.setState({
      loading: true
   });
   fetchData(this.state.text).then(jsonResponse => {
     this.setState({
        loading: false,
        data: jsonResponse
     });
   });
}