反应路由器和 this.props.children - 如何将状态传递给 this.props.children

Posted

技术标签:

【中文标题】反应路由器和 this.props.children - 如何将状态传递给 this.props.children【英文标题】:React router and this.props.children - how to pass state to this.props.children 【发布时间】:2016-06-20 12:38:45 【问题描述】:

我是第一次使用 React-router,但我还不知道如何思考它。这是我在嵌套路由中加载组件的方式。

入口点 .js

ReactDOM.render(
    <Router history=hashHistory >
        <Route path="/" component=App>
            <Route path="models" component=Content>
        </Route>
    </Router>, 
    document.getElementById('app')
);

App.js

  render: function() 
    return (
      <div>
        <Header />
        this.props.children
      </div>
    );
  

所以我的 App 的子组件是我发送的 Content 组件。我正在使用 Flux 并且我的 App.js 具有状态并侦听更改,但我不知道如何将该状态传递给它。道具.儿童。在使用 react-router 之前,我的 App.js 明确定义了所有子节点,因此传递状态很自然,但我现在不知道该怎么做。

【问题讨论】:

How to pass props to this.props.children的可能重复 【参考方案1】:

这个问题归结为,你如何将道具传递给孩子?

2018 年 6 月答案

当今的技术:

反应 16+ React Router 4: react-router-dom Render Props from official docs

假设一些有状态的组件:

import React from 'react'
import  BrowserRouter, Route  from 'react-router-dom'

// some component you made
import Title from './Title'

class App extends React.Component 
  // this.state
  state =  title: 'foo' 

  // this.render
  render() 
    return (
      <BrowserRouter>

        // when the url is `/test` run this Route's render function:
        <Route path="/:foobar" render=

          // argument is props passed from `<Route /`>
          routeProps => 

            // render Title component
            <Title 
              // pass this.state values
              title=this.state.title

              // pass routeProps values (url stuff)
              page=routeProps.match.params.foobar // "test"
            />

         />

      </BrowserRouter>
    )
  

这是因为 this.props.children 是一个函数:

// "smart" component aka "container"
class App extends React.Component 
  state =  foo: 'bar' 
  render() 
    return this.props.children(this.state.foo)
  


// "dumb" component aka "presentational"
const Title = () => (
  <App>
    title => <h1>title</h1>
  </App>
)

Example on codesandbox

我以前不再推荐的老派答案:

使用几个 React 辅助方法,您可以将状态、道具和其他任何东西添加到 this.props.children

render: function() 
  var children = React.Children.map(this.props.children, function (child) 
    return React.cloneElement(child, 
      foo: this.state.foo
    )
  )

  return <div>children</div>

然后你的子组件可以通过 props 访问它,this.props.foo

【讨论】:

是的,我在阅读有关儿童帮手的信息时看到了这个。为什么要使用 Map 而不是 ForEach? 如果你能提供帮助,一般建议不要改变数据。这是一般编程中的好习惯,不仅适用于 React。只有在没有其他可能的解决方案时才进行突变——这种情况很少见。 我同意突变,但我想我没有看到联系 - ForEach 是否一定会突变状态? 好吧cloneElement返回一个新的子对象,所以你需要返回一个新的children数组/对象。 Children.forEach 不返回任何内容,Array.prototype.forEach 也不返回。如果您不返回任何内容,则不会影响任何更改,除非您改变某些内容或引起副作用(保存到数据库/进行 ajax 调用等) 感谢您的回答,就像一个魅力。但是,我收到来自子组件的 propType 验证警告,说道具未定义。我可以毫无问题地使用它们,但我不知道为什么会抛出这些警告?你有什么想法吗?【参考方案2】:

您可以使用React method "cloneElement" 来完成此操作。当你克隆元素时,你可以在那个时候传入道具。在渲染 fn 中使用克隆而不是原始。例如:

    render: function() 
    var childrenWithProps = React.cloneElement(this.props.children, someProp: this.state.someProp);
    return (
      <div>
        <Header />
        childrenWithProps
      </div>
    );
  

【讨论】:

childrenWithProps 周围缺少花括号 在 this.props.children 只有一个元素的情况下,您的示例会克隆所有孩子还是只克隆一个?我在 *** 上看到了另一个示例,但我需要手动遍历它们只是为了传递基本的道具,这似乎是错误的。 @Patrick 如果您查看我的回答,您会首先注意到Children.map。这是必需的,通常是因为children 可以是对象或数组,在后一种情况下,您需要克隆每个元素。 @Patrick 正如@azium 所说,我的示例仅在this.props.children 是单个对象而不是数组时才有效。而且,Children.map 将起作用,即使 this.props.children 是单个对象。所以他们的建议比我的更好。 谢谢!我很高兴得到帮助【参考方案3】:

还可以选择使用Context。 React-Router 依赖它来访问路由组件中的 Router 对象。

来自另一个answer 我提出了一个类似的问题:

我在codepen 上快速整理了一个使用上下文的示例。 MainLayout 定义了一些可以由孩子使用上下文使用的属性:userswidgets。这些属性由UserListWidgetList 组件使用。请注意,他们需要在 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'))

【讨论】:

以上是关于反应路由器和 this.props.children - 如何将状态传递给 this.props.children的主要内容,如果未能解决你的问题,请参考以下文章

反应路由器和路由参数

反应组件和渲染之间的路由器差异

使用 redux 保护的路由和身份验证反应路由器 v4

反应路由器/反应查询不会取消/发出导航请求 - 反应/打字稿

markdown 如何安装和使用反应路由器(路由)

反应路由器和嵌套路由