React router and this.props.children - how to pass state to this.props.children

前端 未结 3 1144
醉酒成梦
醉酒成梦 2020-12-01 10:21

I\'m using React-router for the first time and I don\'t know how to think in it yet. Here\'s how i\'m loading my components in nested routes.

entry point .js

相关标签:
3条回答
  • 2020-12-01 11:06

    There's also the option of using Context. React-Router relies on it to give access to the Router object in the route components.

    From another answer I gave on a similar question:

    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'))
    
    0 讨论(0)
  • 2020-12-01 11:13

    This question boils down to, how do you pass props to children?

    June 2018 answer

    Today's tech:

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

    Assuming some stateful component:

    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 works because this.props.children is a function:

    // "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

    My previous oldschool answer that I wouldn't recommend anymore:

    Using a couple of React helper methods you can add state, props and whatever else to 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>
    }
    

    Then your child component can access this via props, this.props.foo.

    0 讨论(0)
  • 2020-12-01 11:21

    You can use the React method "cloneElement" to accomplish this. When you clone the element, you can pass in props at that time. Use the clone instead of the original in your render fn. eg:

        render: function() {
        var childrenWithProps = React.cloneElement(this.props.children, {someProp: this.state.someProp});
        return (
          <div>
            <Header />
            {childrenWithProps}
          </div>
        );
      }
    
    0 讨论(0)
提交回复
热议问题