【问题标题】:Dispatching Redux actions on location change with react-router-dom使用 react-router-dom 在位置更改时调度 Redux 操作
【发布时间】:2018-10-28 07:28:11
【问题描述】:

我正在将 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>
  }
}

我正在使用来自react-router-domwithRouter,因此在提交搜索时 URL 会更新。

当用户在浏览器中导航返回时会出现问题。 URL 导航返回,props 更新(即props.match.params.term),但搜索没有重新提交。这是因为 submitSearch 操作仅在 SearchForm.constructor(如果 URL 中有术语,则搜索初始加载)和 SearchForm.handleSubmit 中调度。

当 URL 更改时侦听状态更改为 term 的最佳方法是什么,然后分派搜索操作?

【问题讨论】:

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


    【解决方案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
    

    【讨论】:

      【解决方案2】:

      如果新的 props 与当前的 props 不匹配,我目前的解决方案是在 componentWillRecieveProps 生命周期方法中调度 submitSearch

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

      然后,我没有在提交表单时调度操作,而是将新位置推送到 historycomponentWillReceiveProps 进行调度:

      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 原则?我能做得更好吗?

      【讨论】:

        猜你喜欢
        • 2018-12-09
        • 2016-09-21
        • 2018-07-16
        • 2020-09-02
        • 1970-01-01
        • 2019-07-30
        • 2017-09-12
        • 2016-11-17
        • 2018-08-10
        相关资源
        最近更新 更多