我正在使用react-router 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() {
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.js的理解是,数据通常应该作为道具传递给子组件。 在示例中,我正在轮询来自服务器的一些数据,这些数据应由两个不同的子组件使用。因为它是动态数据我把它放在状态。
但是,如果我在同一个组件中定义路由,则react-router会因为重新呈现而崩溃。更新后的状态不会传递给孩子,控制台将打印:
Imagine I am polling data from a server here
Warning: [react-router] You cannot change <Router routes>; it will be ignored
我不喜欢的一种解决方法是使用全局状态来访问数据。这就是我在我的案例中所做的。
这个用例有优雅的解决方案吗?
答案 0 :(得分:4)
选项1: Facebook正在使用contexts提供一种方法。
我在codepen上使用上下文快速汇总了一个示例。 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'))
选项2: 我使用的一个解决方案如下: 在父组件渲染方法中,我做了类似这样的事情:
{this.props.children && React.cloneElement(this.props.children, {
prop1: this.props.prop1,
prop2: this.props.prop2
})}
然后,在作为子路线一部分的所有组件中,他们将自动获得这些属性,并可通过他们的props
访问。
例如,在my project中,Admin
是父组件,请查看其render method。
正如您在routes file中看到的,位于/admin
下的子路径中的组件是PostList
。 PostList
使用的函数getAdminPost
来自Admin
,using its props。
我建议您在单独的文件中定义路线,如react-router tutorial中所述。