Reactjs 如何将状态从路由器传递到子组件
我正在使用react路由器2.0.0。考虑下面的例子:Reactjs 如何将状态从路由器传递到子组件,reactjs,react-router,Reactjs,React Router,我正在使用react路由器2.0.0。考虑下面的例子: import React from 'react'; import ReactDOM from 'react-dom'; import { Router, Route, IndexRoute, hashHistory } from 'react-router'; const Main = React.createClass({ getInitialState() { re
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'));
从“React”导入React;
从“react dom”导入react dom;
从“react Router”导入{Router,Route,IndexRoute,hashHistory};
const Main=React.createClass({
getInitialState(){
返回{数据:0};
},
componentDidMount(){
设置间隔(()=>{
log(“假设我正在从这里的服务器轮询数据”);
this.setState({data:Math.random().toFixed(2)});
}, 2000);
},
render(){
返回
;
}
});
const MainPage=React.createClass({
render(){
返回主页面,数据:{this.props.route.data};
}
});
const Page1=React.createClass({
render(){
返回第1页,数据:{this.props.route.data};
}
});
ReactDOM.render(,document.getElementById('app'));
我对react.js的理解是,数据通常应该作为道具传递给子组件。
在本例中,我正在轮询来自服务器的一些数据,这些数据应该由两个不同的子组件使用。因为它是动态数据,所以我将它置于状态
然而,若我在同一个组件中定义了路由,react路由器就会崩溃,因为它会被重新渲染。更新的状态不会传递给子级,控制台将打印:
Imagine I am polling data from a server here
Warning: [react-router] You cannot change <Router routes>; it will be ignored
假设我正在从服务器轮询数据
警告:[反应路由器]您无法更改;它将被忽略
我不喜欢的一种解决方法是使用全局状态来访问数据。我就是这么做的
这个用例有一个优雅的解决方案吗?选项1:Facebook提供了一种通过使用
我很快用上下文将一个例子放在一起
MainLayout
定义了一些可由使用上下文的子级使用的属性:users
和widgets
。这些属性由UserList
和WidgetList
组件使用。注意,它们需要在contextTypes
对象中定义从上下文访问所需的内容
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'))
然后,在作为子路由一部分的所有组件中,它们将自动获得这些属性,并且可以通过它们的道具
访问这些属性
例如,在中,Admin
是父组件,请检查其
如中所示,位于/admin
下的子路由中的组件是PostList
PostList
正在使用来自Admin
的函数getAdminPost
我建议您在单独的文件中定义路由,如中所述。让我将该解决方案转移到我的示例中:我将引入一个新组件,如:
。将数据存储在其状态,并使其通过您描述的cloneElement
内容传播数据更新。嗯,很有趣,至少这避免了全球状态,但感觉真的很不舒服。这就像手动执行react.js应该处理的状态道具更新一样。此外,道具传递实际上隐藏在DataComponent
中。在HTML中将其显式地作为属性更容易掌握。我同意这也不是一个很好的解决方案。现在,我想起来了,我记得我在看,只是我不记得为什么我没有使用它们,并决定去解决这个问题。上下文是这样做的官方解决方案,但他们不建议滥用它。理想情况下,如果您知道您的子组件,您只需将属性作为属性传递给它们。作为属性传递实际上不起作用,这就是我的示例所做的。当你有状态的时候它就不起作用了,因为当它被重新渲染的时候路由器会断开MainLayout
定义了一些可由使用上下文的子级使用的属性:users
和widgets
。这些属性由UserList
和WidgetList
组件使用。注意,他们需要从代码中的上下文中定义他们需要访问的内容。虽然脸谱网认为上下文是实验性的,但是<代码>反应路由器项目严重依赖于它。无论何时,只要您想以编程方式导航到路由,就需要访问路由器对象,这可以通过上下文完成:
{this.props.children && React.cloneElement(this.props.children, {
prop1: this.props.prop1,
prop2: this.props.prop2
})}