嗨,大家好,
我在最新的应用程序中使用react-router和redux,并且遇到了一些与基于当前url参数和查询所要求的状态更改有关的问题。
基本上,我有一个组件,每次URL更改时都需要更新其状态。 像这样通过装饰器通过redux通过props传递状态
@connect(state => ({
campaigngroups: state.jobresults.campaigngroups,
error: state.jobresults.error,
loading: state.jobresults.loading
}))
目前,我正在使用componentWillReceiveProps
生命周期方法来响应来自react-router的url更改,因为当url中的this.props.params
和this.props.query
更改时,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);
}
}
是否有基于路线转换触发动作的标准方法,还是可以将商店的状态直接连接到组件的状态,而不是通过prop传递它? 我尝试使用willTransitionTo
静态方法,但是无法访问this.props.dispatch。
@deowk您可以将this.props
与nextProps
进行比较,以查看相关数据是否发生了变化。 如果它没有改变,那么您不必再次触发该动作,就可以摆脱无限循环。
@johanneslumpe :在我的情况下,campaigngroup是一个相当大的对象集合,以这种方式使用深度对象比较作为条件似乎效率不高?
@deowk如果使用不可变数据,则可以只比较引用
@deowk ,这个问题有两个部分。 第一个是componentWillReceiveProps()
不是响应状态变化的理想途径-主要是因为它迫使你认为势在必行,而不是被动地像我们与终极版做。 解决方案是在商店中存储您当前的路由器信息(位置,参数,查询)。 然后,您所有的状态都在同一个地方,您可以使用与其余数据相同的Redux API对其进行订阅。
诀窍是创建一个在路由器位置更改时将触发的操作类型。 在即将推出的React Router 1.0版本中,这很容易:
// 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) })} />
问题的第二部分是您需要一种对视图层外部的Redux状态更改做出反应的方法,例如响应路径更改而触发操作。 如果需要,您可以继续使用componentWillReceiveProps处理简单情况,例如您描述的情况。
但是,对于更复杂的事情,我建议您使用RxJS(如果您愿意的话)。 这正是可观察对象设计的目的-反应性数据流。
要在Redux中执行此操作,请首先创建一个可观察的存储状态序列。 您可以使用redux-rx的observableFromStore()
。
import { observableFromStore } from 'redux-rx';
const state$ = observableFromStore(store);
然后,只需使用可观察的运算符来订阅特定的状态更改即可。 这是成功登录后从登录页面重定向的示例:
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()
等命令性模式的相同功能相比,此实现要简单得多。
希望有帮助!
我们在新文档中需要它。 写得很好。
@acdlite :非常感谢,您的建议确实对我有很大帮助,尽管如此,我仍在努力--通过触发动作创建者以响应URL更改来更改商店中的状态。
我想在willTransitionTo静态方法中触发动作创建者,因为这似乎是react-router v0.13.3中的唯一选项
class Results extends Component {
..........
}
Results.willTransitionTo = function (transition, params, query) {
// how do I get a reference to dispatch here?
};
@deowk我的猜测是,您直接在redux实例上调用dispatch
:
const redux = createRedux(stores);
BrowserHistory.listen(location => redux.dispatch(routeLocationDidUpdate(location)));
@deowk我目前在反应路由器0.13.3中分派我的网址更改,如下所示:
Router.run(routes, Router.HistoryLocation, function(Handler, locationState) {
dispatch(routeLocationDidUpdate(locationState))
React.render(<Handler/>, appEl);
});
@acdlite真的很好解释! :+1:
同意它也应该在新文档中:)
只是注意, BrowserHistory.history()
已更改为BrowserHistory.addChangeListener()
。
https://github.com/rackt/react-router/blob/master/modules/BrowserHistory.js#L57
编辑:
可能看起来像这样:
history.addChangeListener(() => store.dispatch(routeLocationDidUpdate(location)));
那个减速器@pburtchaell的初始状态又如何呢?
我有以下设置:
// client.js
class App extends Component {
constructor(props) {
super(props);
this.history = new HashHistory();
}
render() {
return (
<Provider store={store}>
{renderRoutes.bind(null, this.history)}
</Provider>
);
}
}
// routes.js
export default function renderRoutes(history) {
// When the route changes, dispatch that information to the store.
history.addChangeListener(() => store.dispatch(routeLocationDidUpdate(location)));
return (
<Router history={history}>
<Route component={myAppView}>
<Route path="/" component={myHomeView} />
</Route>
</Router>
);
};
每次路线更改和应用首次加载时,都会触发routeLocationDidUpdate()
操作创建者。
@pburtchaell您可以分享您的routeLocationDidUpdate
吗?
@gyzerok当然。 它是一个动作创造者。
// actions/location.js
export function routeLocationDidUpdate(location) {
return {
type: 'LOCATION_UPDATE',
payload: {
...location,
},
};
}
@pburtchaell,所以在您的示例中,我不会安静地了解您在哪里获取特定路由的数据必需数据
这是我上面的示例的完整版本:
https://github.com/acdlite/redux-react-router/blob/master/README.md#bonus -reacting-to-state-changes-with-redux-rx
我假设@pburtchaell将使用该代码的异步版本来获取数据(从REST调用等)。 我不确定那是什么? 我假设它会去一家商店,但那家商店会成为locationStore我
<strong i="7">@connect</strong>
进来说
<Comments />
哪些已经“连接”(订阅)到commentStore? 还是仅在commentStore中添加注册这些位置操作?
像这样的网址
/comments/123
总是会被“耦合”到评论组件,那么我该如何重用它呢? 对不起,这很愚蠢,在这里很困惑。 我可以找到一个可靠的例子。
我也在对此进行努力,弄清楚如何调用我的静态fetchData(dispatch, params)
方法(静态,因为服务器在初始渲染之前调用它来调度异步FETCH动作)。
由于上下文中存在对dispatch
的引用,因此我想为fetchData
客户端调用获取此内容的最简单方法是类似Connector
的组件,该组件调用fetchData
或shouldFetchData
,或者让select
回调获得对dispatch
的引用以及state
,因此我们可以检查当前状态为store
并根据需要调度FETCH
操作。
后者更为简洁,但打破了select
应该保持纯函数的事实。 我将研究前者。
我的解决方案是这样的,尽管它非常适合我的设置(静态fetchData(dispatch, state)
方法调度异步_FETCH
操作),但它会使用适当的属性调用传递给它的所有回调: https:// gist.github.com/grrowl/6cca2162e468891d8128 —但是,由于不使用willTransitionTo,因此您将无法延迟页面的转换。
我们绝对需要添加文档! 在“使用react-router使用”部分中可能。
1.0版发布后,我们将提供一种正式的方法。
很高兴听到@gaearon。
然后,只需使用可观察的运算符来订阅特定的状态更改即可。
我已经设置了一个可观察的流,以使我的商店与任何路线更改保持同步,并且我也有一个流设置来监视我的商店。 当我的商店中的值发生更改时,尤其是由于成功在我的应用程序中的其他位置提交表单而使它从undefined
变为有效字符串时,我有兴趣过渡到新路线。
这两个流已设置并正常工作,并且正在更新存储,但是我对Rx还是陌生的,并且在可观察的查询中遇到了麻烦...任何指针? 我在正确的轨道上吗? 可以肯定的是,它与distinctUntilChanged
但是目前正在烘烤我的面条,任何帮助表示赞赏:)
编辑:阿克! 对不起,回答了我自己的问题。 下面的伪代码。 让我知道它看起来是否很恐怖?
const didChangeProject$ = state$
.distinctUntilChanged(state => state.project._id)
.filter(state => typeof state.project._id !== 'undefined');
以#177结束。 在记录路由时,我们需要涵盖所有情况:状态更改时重定向,请求回调时重定向等。
我知道这是关闭的..但是现在使用React 0.14和beta中的各种1.0依赖项,是否对此进行了更新,如果没有,可以围绕React 0.14,react-router,redux等新功能进行教程吗?书面? 我们当中似乎有很多人试图同时了解/理解所有这些,以跟上即将发生的变化。 我知道事情处于不断变化的状态(双关..呃。与路由。 很可能是我自己的错,因为我仍在努力理解所有这些工作原理,只是希望很快就可以得到包含最新内容的更新教程。
除非有教程,否则请随意看一下具有路由的examples/real-world
。 现在还不是“最新和最好的”,但可以正常工作。
最有用的评论
@deowk ,这个问题有两个部分。 第一个是
componentWillReceiveProps()
不是响应状态变化的理想途径-主要是因为它迫使你认为势在必行,而不是被动地像我们与终极版做。 解决方案是在商店中存储您当前的路由器信息(位置,参数,查询)。 然后,您所有的状态都在同一个地方,您可以使用与其余数据相同的Redux API对其进行订阅。诀窍是创建一个在路由器位置更改时将触发的操作类型。 在即将推出的React Router 1.0版本中,这很容易:
现在,您的存储状态将始终与路由器状态同步。 这就解决了手动响应查询参数更改和上面组件中的
setState()
-只需使用Redux的连接器即可。问题的第二部分是您需要一种对视图层外部的Redux状态更改做出反应的方法,例如响应路径更改而触发操作。 如果需要,您可以继续使用componentWillReceiveProps处理简单情况,例如您描述的情况。
但是,对于更复杂的事情,我建议您使用RxJS(如果您愿意的话)。 这正是可观察对象设计的目的-反应性数据流。
要在Redux中执行此操作,请首先创建一个可观察的存储状态序列。 您可以使用redux-rx的
observableFromStore()
。然后,只需使用可观察的运算符来订阅特定的状态更改即可。 这是成功登录后从登录页面重定向的示例:
与使用
componentDidReceiveProps()
等命令性模式的相同功能相比,此实现要简单得多。希望有帮助!