使用react-router-dom调度位置更改时的Redux操作

时间:2018-05-17 22:38:04

标签: reactjs redux react-redux redux-thunk react-router-dom

我正在使用React和Redux作为搜索应用程序。使用react-router-dom,我将/search/:term?发送到Search组件:

<Router>
  <Switch>
    <Route exact path="/search/:term?" component={Search} />
    <Redirect to="/search" />
  </Switch>

const Search = (props) => {
  const { term } = props.match.params;
  return (
    <div>
      <SearchForm term={term}/>
      <SearchResults />
    </div>
  )
};

当用户在SearchForm组件中提交搜索时,我正在调度提交搜索查询的操作。如果给出一个术语,我也在构造函数中启动搜索,最初:

class SearchForm extends Component {
  constructor(props) {
    super(props);

    const term = props.term ? props.term : '';
    this.state = {
      term: term,
    }

    if (term) {
      this.props.submitSearch(term);
    }
  }

  handleSubmit = (e) => {
    e.preventDefault();
    if (this.state.term) {
      this.props.submitSearch(this.state.term);
    }
  }

  render = () => {
    <form
      onSubmit={this.handleSubmit.bind(this)}>
      ...
    </form>
  }
}

我正在使用withRouter中的react-router-dom,因此在提交搜索时会更新网址。

当用户在浏览器中导航回来时会出现问题。 URL导航回来,道具更新(即props.match.params.term),但搜索不会重新提交。这是因为submitSearch操作仅在SearchForm.constructor(如果网址中包含字词时搜索初始加载)和SearchForm.handleSubmit进行调度。

当网址发生变化时,调整状态更改为term的最佳方法是什么,然后发送搜索操作?

2 个答案:

答案 0 :(得分:1)

我会在componentDidMount中检索路由参数,因为您正在推送新路线并因此重新加载视图。

在您的SearchForm中,它看起来像这样。

state = {
  term: '';
}

onChange = (term) => this.setState({ term })

onSubmit = () => this.props.history.push(`/search/${this.state.term}`);

在你的SearchResult中:

componentDidMount() {
  this.props.fetchResults(this.props.term)
}

一件好事就是保持SearchResult组件干燥。有几种方法可以实现,使用higher order components aka HOC

export default FetchResultsHoc(Component) => {

  @connect(state => ({ results: state.searchResults }))
  class FetchResults extends React.Component {
    componentDidMount(){
      dispatch(fetchResults(this.props.match.params.term))
    }

    render(){
      <Component {...this.props} />
    }
  }

  return FetchResultsHoc;
}

然后,您将使用装饰器调用您的SearchResult组件。

import { fetchResults } from './FetchResultsHoc';

@fetchResults
export default class SearchResult extends React.PureComponent { ... }
// You have now access to this.props.results inside your class

答案 1 :(得分:0)

我目前的解决方案是,如果新道具与当前道具不匹配,则在submitSearch生命周期方法中发送componentWillRecieveProps

componentWillReceiveProps(nextProps) {
  if (this.props.term !== nextProps.term) {
    this.setState({
      term: nextProps.term,
    });
    this.props.submitSearch(nextProps.term);
  }
}

然后,我不是在表单提交上调度操作,而是将新位置推送到history,并componentWillReceiveProps执行调度:

handleSubmit = (e) => {
  e.preventDefault();
  if (this.state.term) {
    this.props.history.push('/search/'+this.state.term);
  }
}

这个解决方案感觉有些不对劲,但它确实有效。 (其他人似乎同意:Evil things you do with redux — dispatch in updating lifecycle methods

这样做是否违反了React或Redux原则?我能做得更好吗?