首页 文章

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

提问于
浏览
0

我正在使用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 .

The problem happens when the user navigates Back in their browser. URL导航回来,道具更新(即 props.match.params.term ),但搜索不会重新提交 . 这是因为 submitSearch 动作仅在 SearchForm.constructor (如果术语在URL中的初始加载时搜索)和 SearchForm.handleSubmit 中调度 .

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

2 回答

  • 0

    我会在 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

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

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

相关问题