当路由器改变道具时,如何以及在何处调度动作

时间:2018-06-06 12:01:27

标签: reactjs redux react-router

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

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

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

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

[UPDATE]

到目前为止,这是解决方案:

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

它还检查路由器天参数是否发生了变化,如果是,则将dispatchFetch设置为true。

这将导致render函数异步调度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 个答案:

答案 0 :(得分:1)

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

<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;
  }

答案 1 :(得分:1)

您是否尝试过componentWillReceiveProps?

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

答案 2 :(得分:0)

要在路由器中为路由添加参数,请执行此操作

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

这意味着现在&#34; / sessions /&#34;溃败有一个名为&#34; prefDay&#34; 示例/会话/:prefDay

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

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

您可以像这样从获取此值

this.props.match.params.prefDay

答案 3 :(得分:0)

在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();
    }

从渲染功能中删除了代码。现在当它安装它时,它将调度操作来加载数据,当路由发生变化时,它将再次发送它,但不会在更新周期中发送。