如何将状态从路由器传递到子组件 [英] How to pass state from a Router to a Sub-Component

查看:29
本文介绍了如何将状态从路由器传递到子组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是 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 <路由器历史记录={hashHistory}><路由路径="/"><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 定义了一些可以由使用上下文的子级使用的属性:userswidgets.UserListWidgetList 组件使用这些属性.请注意,他们需要在 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.

    这篇关于如何将状态从路由器传递到子组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    相关文章
    其他开发最新文章
    热门教程
    热门工具
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆