当前位置: 首页 > 知识库问答 >
问题:

触发Redux操作以响应React路由器中的路由转换

萧心远
2023-03-14

我在最新的应用程序中使用react router和redux,我面临着一些与基于当前url参数和查询所需状态更改相关的问题。

基本上,我有一个组件,需要在每次url更改时更新它的状态。状态是通过redux的道具传递给decorator的,就像这样

 @connect(state => ({
   campaigngroups: state.jobresults.campaigngroups,
   error: state.jobresults.error,
   loading: state.jobresults.loading
 }))

目前,我正在使用componentWillReceiveProps生命周期方法来响应来自react-router的url更改,因为当this.props.params和this.props.query中的url更改时,react-router将向处理程序传递新的props-此方法的主要问题是,我在该方法中触发一个操作以更新状态-然后将新的道具传递给组件,组件将再次触发相同的生命周期方法-因此基本上创建了一个无休止的循环,目前我正在设置一个状态变量来阻止这种情况发生。

  componentWillReceiveProps(nextProps) {
    if (this.state.shouldupdate) {
      let { slug } = nextProps.params;
      let { citizenships, discipline, workright, location } = nextProps.query;
      const params = { slug, discipline, workright, location };
      let filters = this._getFilters(params);
      // set the state accroding to the filters in the url
      this._setState(params);
      // trigger the action to refill the stores
      this.actions.loadCampaignGroups(filters);
    }
  }

是否有基于路由转换触发操作的标准方法,或者我是否可以将存储的状态直接连接到组件的状态,而不是通过道具传递?我已经尝试使用WillTransition静态方法,但是我没有访问this.props.dispatch的权限。

共有2个答案

邬博涉
2023-03-14

如前所述,解决方案分为两部分:

为此,您所要做的就是设置react router redux。按照指示去做,你会没事的。

设置完所有内容后,您应该有一个路由状态,如下所示:

在代码的某个地方,您现在应该有这样的东西:

// find this piece of code
export default function configureStore(initialState) {
    // the logic for configuring your store goes here
    let store = createStore(...);
    // we need to bind the observer to the store <<here>>
}

您要做的是观察存储中的更改,以便在某些内容发生更改时分派操作。

正如@deook提到的,您可以使用rx,也可以编写自己的观察者:

reduxStoreObserver.js

var currentValue;
/**
 * Observes changes in the Redux store and calls onChange when the state changes
 * @param store The Redux store
 * @param selector A function that should return what you are observing. Example: (state) => state.routing.locationBeforeTransitions;
 * @param onChange A function called when the observable state changed. Params are store, previousValue and currentValue
 */
export default function observe(store, selector, onChange) {
    if (!store) throw Error('\'store\' should be truthy');
    if (!selector) throw Error('\'selector\' should be truthy');
    store.subscribe(() => {
        let previousValue = currentValue;
        try {
            currentValue = selector(store.getState());
        }
        catch(ex) {
            // the selector could not get the value. Maybe because of a null reference. Let's assume undefined
            currentValue = undefined;
        }
        if (previousValue !== currentValue) {
            onChange(store, previousValue, currentValue);
        }
    });
}

现在,您所要做的就是使用我们刚刚编写的reduxStoreObserver.js来观察更改:

import observe from './reduxStoreObserver.js';

export default function configureStore(initialState) {
    // the logic for configuring your store goes here
    let store = createStore(...);

    observe(store,
        //if THIS changes, we the CALLBACK will be called
        state => state.routing.locationBeforeTransitions.search, 
        (store, previousValue, currentValue) => console.log('Some property changed from ', previousValue, 'to', currentValue)
    );
}

上面的代码使我们的函数在每次LocationBeforeTransformations.search状态发生更改时都被调用(这是用户导航的结果)。如果需要,可以观察que查询字符串等。

如果您希望由于路由更改而触发操作,则只需在处理程序内部执行store.dispatch(yourAction)

澹台正业
2023-03-14

好吧,我最终在redux的github页面上找到了答案,所以我将在这里发布。希望它能帮别人省去一些痛苦。

@我认为这个问题有两个方面。首先,componentWillReceiveProps()不是响应状态更改的理想方式——主要是因为它迫使您必须思考,而不是像我们使用Redux那样被动思考。解决方案是将当前路由器信息(位置、参数、查询)存储在存储区内。然后,您的所有状态都位于同一位置,您可以使用与其余数据相同的reduxapi订阅它。

诀窍是创建一个动作类型,每当路由器位置发生变化时就会触发。这在即将发布的1.0版本的React路由器中很容易:

// routeLocationDidUpdate() is an action creator
// Only call it from here, nowhere else
BrowserHistory.listen(location => dispatch(routeLocationDidUpdate(location)));

现在,您的存储状态将始终与路由器状态同步。这解决了手动响应查询参数更改和上面组件中setState()的需要——只需使用Redux的连接器。

<Connector select={state => ({ filter: getFilters(store.router.params) })} />

问题的第二部分是,您需要一种对视图层之外的重复使用状态更改作出反应的方法,例如,对路由更改触发一个操作。如果愿意,您可以继续将componentWillReceiveProps用于您描述的简单案例。

不过,对于任何更复杂的问题,如果您愿意,我建议您使用RxJS。这正是可观测数据的设计目的——反应式数据流。

要在Redux中做到这一点,首先创建一个可观察的存储状态序列。您可以使用rx的可观察的FromStore()来实现这一点。

按CNP建议编辑

import { Observable } from 'rx'

function observableFromStore(store) {
  return Observable.create(observer =>
    store.subscribe(() => observer.onNext(store.getState()))
  )
}

然后就是使用可观察的操作符来订阅特定的状态变化。以下是成功登录后从登录页面重新定向的示例:

const didLogin$ = state$
  .distinctUntilChanged(state => !state.loggedIn && state.router.path === '/login')
  .filter(state => state.loggedIn && state.router.path === '/login');

didLogin$.subscribe({
   router.transitionTo('/success');
});

此实现比使用命令式模式(如componentDidReceiveProps())的相同功能简单得多。

 类似资料:
  • 问题内容: 我在最新的应用程序中使用react-router和redux,并且遇到了一些与基于当前url参数和查询所要求的状态更改有关的问题。 基本上,我有一个组件,每次URL更改时都需要更新其状态。像这样通过装饰器通过redux通过props传递状态 目前,我正在使用componentWillReceiveProps生命周期方法来响应来自react- router的url更改,因为当this.p

  • 使用redux和反应路由器,我想访问路由指定的组件以外的组件上的路由参数。 我已经对react-router、redux和react-router-redux进行了如下设置,我想从我的redux存储访问reportId参数。 我已经尝试连接react-redux路由器来存储路由状态,但是我发现除了活动路由的完整路径之外,redux内部没有任何有用的存储。这让我可以选择从redux中的路径解析出re

  • 我正在使用react路由器v4和redux,如果用户未登录,我想使用私有和受保护的路由重定向。 我有一个路由组件: 它是这样实现的: 这是私人路线: 传递prop的最佳方式是什么,如果我连接Routes组件并从那里传递是否可以,或者应该从其他地方传递,或者连接需要它的每个组件并从那里读取?此外,这种方法如何处理嵌套路由,如?谢谢

  • 如果我将路由折叠起来,这样看起来就像: 工作很好。我嵌套的原因是因为我将在“dashboard”下有多个子项,并且希望它们都在URL中以为前缀。

  • 我有一个简单的(目前)应用程序,使用react router和redux,我想为它添加国际化功能。 我已经安装了npm包,并且能够安装和运行提供的示例。我已经将适当的导入添加到我自己的应用程序中,并将国际化标签添加到根渲染方法中。 当我将I18nextProvider标记添加到render方法时,我得到了错误 找不到模块“react” 这并不是特别有用,尤其是因为如果我删除标签,react应用程序