![the the](https://c1.lmlphp.com/image/static/default_avatar.gif)
本文介绍了如何将状态从路由器传递到子组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我使用的是 react-router 2.0.0.考虑以下示例:
import React from 'react';从 'react-dom' 导入 ReactDOM;从'react-router'导入{路由器,路由,索引路由,hashHistory};const Main = React.createClass({getInitialState() {返回{数据:0};},componentDidMount() {setInterval(() => {console.log("假设我正在从这里的服务器轮询数据");this.setState({data: Math.random().toFixed(2)});}, 2000);},使成为() {return <路由路径="/"><IndexRoute component={MainPage} data={this.state.data}/><Route path="page1" component={Page1} data={this.state.data}/></路线></路由器>;}});const MainPage = React.createClass({使成为() {返回<div>MainPage,数据:{this.props.route.data}</div>;}});const Page1 = React.createClass({使成为() {返回<div>Page1,数据:{this.props.route.data}</div>;}});ReactDOM.render(, document.getElementById('app'));
我对 react.js 的理解是数据通常应该作为 props 传递给子组件.在示例中,我正在轮询来自服务器的一些数据,这些数据应该由两个不同的子组件使用.由于是动态数据,我把它放在状态中.
然而,如果我在同一个组件中定义路由,react-router 就会因为它被重新渲染而崩溃.更新后的状态不会传递给孩子,控制台会打印:
想象一下,我正在从这里的服务器轮询数据警告:[react-router] 你不能改变 <Router routes>;它将被忽略
我不喜欢的一种解决方法是使用全局状态来访问数据.这就是我在我的情况下所做的.
是否有针对此用例的优雅解决方案?
解决方案
选项 1: Facebook 提供了一种使用 上下文.
我在 codepen 上快速组合了一个使用上下文的示例.MainLayout
定义了一些可以由使用上下文的子级使用的属性:users
和 widgets
.UserList
和 WidgetList
组件使用这些属性.请注意,他们需要在 contextTypes
对象中定义他们需要从上下文访问的内容.
var { Router, Route, IndexRoute, Link } = ReactRoutervar MainLayout = React.createClass({子上下文类型:{用户:React.PropTypes.array,小部件:React.PropTypes.array,},getChildContext:函数(){返回 {用户:[丹"、瑞安"、迈克尔"]、小部件:[小部件 1"、小部件 2"、小部件 3"]};},渲染:函数(){返回 (<div className="app"><header className="primary-header"></header><aside className="primary-aside"><ul><li><Link to="/">主页</Link></li><li><Link to="/users">用户</Link></li><li><Link to="/widgets">小部件</Link></li></一边><主要>{this.props.children}</main>
)}})var Home = React.createClass({渲染:函数(){返回(
主页
)}})var SearchLayout = React.createClass({渲染:函数(){返回 (<div className="搜索"><header className="search-header"></header><div className="结果">{this.props.children}
<div className="search-footer 分页"></div>
)}})var UserList = React.createClass({上下文类型:{用户:React.PropTypes.array},渲染:函数(){返回 (<ul className="用户列表">{this.context.users.map(function(user, index) {return
{user}
;})})}})var WidgetList = React.createClass({上下文类型:{小部件:React.PropTypes.array},渲染:函数(){返回 (<ul className="widget-list">{this.context.widgets.map(function(widget, index) {return {widget};})})}})var Routes = React.createClass({渲染:函数(){返回<路由器><Route path="/" component={MainLayout}><IndexRoute 组件={Home}/><路由组件={SearchLayout}><Route path="users" component={UserList}/><Route path="widgets" component={WidgetList}/></路线></路线></路由器>;}})ReactDOM.render(, document.getElementById('root'))
选项 2:我正在使用的一种解决方案如下:在父组件的渲染方法中,我是这样做的:
{this.props.children &&React.cloneElement(this.props.children, {prop1: this.props.prop1,prop2:this.props.prop2})}
然后在属于子路由的所有组件中,它们将自动获取这些属性,并且可以通过它们的 props
访问.
例如,在我的项目中,Admin
是父组件,查看它的 渲染方法.
正如您在 routes 文件中所见是/admin
下子路由中的一个组件,就是PostList
.PostList
正在使用 getAdminPost
函数,它来自 Admin
,使用其道具.
我建议您在单独的文件中定义路由,如 反应路由器教程.
I am using react-router 2.0.0. Consider the following example:
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, IndexRoute, hashHistory } from 'react-router';
const Main = React.createClass({
getInitialState() {
return {data: 0};
},
componentDidMount() {
setInterval(() => {
console.log("Imagine I am polling data from a server here");
this.setState({data: Math.random().toFixed(2)});
}, 2000);
},
render() {
return <Router history={hashHistory}>
<Route path="/">
<IndexRoute component={MainPage} data={this.state.data}/>
<Route path="page1" component={Page1} data={this.state.data}/>
</Route>
</Router>;
}
});
const MainPage = React.createClass({
render() {
return <div>MainPage, data: {this.props.route.data}</div>;
}
});
const Page1 = React.createClass({
render() {
return <div>Page1, data: {this.props.route.data}</div>;
}
});
ReactDOM.render(<Main />, document.getElementById('app'));
My understanding of react.js is that data should usually be passed to child components as props.In the example I am polling some data from a server that should be used by two different child components. Since it is dynamic data I put it in the state.
However, if I define routing in that same component, react-router breaks down because it gets re-rendered. The updated state will not be passed to the child and the console will print:
Imagine I am polling data from a server here
Warning: [react-router] You cannot change <Router routes>; it will be ignored
One workaround that I dislike is to use global state to access the data. Which is what I did in my case.
Is there an elegant solution to this use-case?
解决方案
Option 1: Facebook is offering a way to do this using contexts.
I quickly put together an example using contexts on codepen. MainLayout
defines some properties that could be used by the children using the context: users
and widgets
. These properties are used by the UserList
and WidgetList
components. Notice they need to define what they need to access from the context in the contextTypes
object.
var { Router, Route, IndexRoute, Link } = ReactRouter
var MainLayout = React.createClass({
childContextTypes: {
users: React.PropTypes.array,
widgets: React.PropTypes.array,
},
getChildContext: function() {
return {
users: ["Dan", "Ryan", "Michael"],
widgets: ["Widget 1", "Widget 2", "Widget 3"]
};
},
render: function() {
return (
<div className="app">
<header className="primary-header"></header>
<aside className="primary-aside">
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/users">Users</Link></li>
<li><Link to="/widgets">Widgets</Link></li>
</ul>
</aside>
<main>
{this.props.children}
</main>
</div>
)
}
})
var Home = React.createClass({
render: function() {
return (<h1>Home Page</h1>)
}
})
var SearchLayout = React.createClass({
render: function() {
return (
<div className="search">
<header className="search-header"></header>
<div className="results">
{this.props.children}
</div>
<div className="search-footer pagination"></div>
</div>
)
}
})
var UserList = React.createClass({
contextTypes: {
users: React.PropTypes.array
},
render: function() {
return (
<ul className="user-list">
{this.context.users.map(function(user, index) {
return <li key={index}>{user}</li>;
})}
</ul>
)
}
})
var WidgetList = React.createClass({
contextTypes: {
widgets: React.PropTypes.array
},
render: function() {
return (
<ul className="widget-list">
{this.context.widgets.map(function(widget, index) {
return <li key={index}>{widget}</li>;
})}
</ul>
)
}
})
var Routes = React.createClass({
render: function() {
return <Router>
<Route path="/" component={MainLayout}>
<IndexRoute component={Home} />
<Route component={SearchLayout}>
<Route path="users" component={UserList} />
<Route path="widgets" component={WidgetList} />
</Route>
</Route>
</Router>;
}
})
ReactDOM.render(<Routes/>, document.getElementById('root'))
Option 2:One solution I am using is the following:In the parent component render method, I do something like this:
{this.props.children && React.cloneElement(this.props.children, {
prop1: this.props.prop1,
prop2: this.props.prop2
})}
Then in all the components which are part of a child route, they will get these properties automatically, and can be accessed through their props
.
For example, in my project, Admin
is the parent component, check out its render method.
As you can see in the routes file, a component which is in a child route under /admin
, is PostList
. PostList
is using the function getAdminPost
which is coming from Admin
, using its props.
I suggest you define the routes in a separate file, like described in the react-router tutorial.
这篇关于如何将状态从路由器传递到子组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!