当react-router更改props时如何以及在何处分派动作

IT技术 reactjs redux react-router
2021-05-10 06:12:58

我可能在这里遗漏了一些东西,使用 Link 更改 react-router 参数将导致props随新参数更改并触发更新周期。

您不能在更新周期中调度操作,但这是参数可用的唯一地方。当我的无状态组件中的 day 参数发生变化时,我需要获取新数据。

该组件有 2 个链接,前一天和后一天。前一天看起来像这样:

<Link to={"/sessions/" + prefDay}>{prefDay}</Link>

[更新]

这是迄今为止的解决方案:

Overview 组件只是一个接受 props 并返回 jsx 的函数,下面是检查日期是否设置的容器,如果不是,它将重定向。如果设置了日期,那么它将返回概览。

它还检查路由器日期参数是否更改,如果更改,则将 dispatchFetch 设置为 true。

这将导致渲染函数异步调度 getData 操作。

不确定是否有另一种方法可以做到这一点,我更喜欢从路由器监听事件并从那里分派事件,但没有(工作)方法来监听路由器。

import { connect } from 'react-redux';
import React, { Component } from 'react';
import Overview from '../components/Overview';
import { getData } from '../actions';
import { selectOverview } from "../selectors";
import { Redirect } from "react-router-dom";


const defaultDate = "2018-01-02";
const mapStateToProps = (lastProps => (state, ownProps) => {
  var dispatchFetch = false;
  if (lastProps.match.params.day !== ownProps.match.params.day) {
    lastProps.match.params.day = ownProps.match.params.day;
    dispatchFetch = true;
  }
  return {
    ...selectOverview(state),
    routeDay: ownProps.match.params.day,
    dispatchFetch
  }
})({ match: { params: {} } });
const mapDispatchToProps = {
  getData
};
class RedirectWithDefault extends Component {
  render() {
    //I would try to listen to route change and then dispatch getData when
    //  routeDay changes but none of the methods worked
    //  https://github.com/ReactTraining/react-router/issues/3554
    //    onChange in FlexkidsApp.js never gets called and would probably 
    //      result in the same problem of dispatching an event in update cycle
    //    browserHistory does not exist in react-router-dom
    //    this.props.history.listen didn't do anything when trying it in the constructor
    //So how does one dispatch an event when props change in stateless components?
    //  can try to dispatch previous and next day instead of using Link component
    //  but that would not update the url in the location bar
    if (this.props.dispatchFetch) {
      Promise.resolve().then(() => this.props.getData(this.props.routeDay));
    }
    return (this.props.routeDay)//check if url has a date (mapStateToProps would set this)
      ? Overview(this.props)
      : <Redirect//no date, redirect
        to={{
          pathname: "/list/" + defaultDate
        }}
      />
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(RedirectWithDefault);
4个回答

最初我希望你的路由器像,

<Route path="/sessions/:prefDay" component={MyComponent}/>

您必须在 getDerivedStateFromProps() 中执行此操作,

static getDerivedStateFromProps(nextProps, prevState) {
    if (prevState.prefDay !== nextProps.match.params.prefDay) {

     return {
     prefDay: nextProps.match.params.prefDay,
     };
   }
   // Return null to indicate no change to state.
   return null;
  }

你试过 componentWillReceiveProps 吗?

componentWillReceiveProps(props){
   if(this.props.data != props.data && this.props.state.routeDay){
     this.props.getData(props.state.routeDay);
   }
}

要将参数添加到您需要在路由器中的路由,请执行此操作

<Route 
     path="/sessions/:prefDay" 
                ....
/>  

这意味着现在 "/sessions/" 路由有一个名为 "prefDay" 的参数 示例 /sessions/:prefDay

现在在Link组件中需要添加这个参数

<Link to={"/sessions/" + prefDay}>{prefDay}</Link>

您可以像这样从 url 获取此值

this.props.match.params.prefDay

在 RedirectWithDefaults 这是无状态组件的容器中,我添加了 componentDidMount(不是更新循环方法):

const historyListener = (lastDay => (props,currentDay) => {
    if(lastDay !== currentDay){
        lastDay = currentDay;
        if(!isNaN(new Date(currentDay))){
            console.log("getting:",currentDay);
            props.getData(currentDay);
        }
    }
})(undefined);

class RedirectWithDefault extends Component {
    componentDidMount(history) {
        this.props.getData(this.props.routeDay || defaultDate);
        this.unListen = this.props.history.listen((location) => {
            historyListener(
                this.props,
                location.pathname.split('/').slice(-1)[0]
            );
        });
    }
    componentWillUnmount(){
        this.unListen();
    }

从渲染函数中删除了代码。现在,当它挂载时,它会分派加载数据的动作,当路由改变时,它会再次分派它,但不会在更新周期中。