2016-03-07 2 views
24

Я использую React-router в первый раз, и я не знаю, как думать в нем еще. Вот как я загружаю свои компоненты во вложенные маршруты.React router и this.props.children - как передать состояние this.props.children

точка входа .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> 
    ); 
    } 

Так ребенок моего приложения является содержание компонента Я послал. Я использую Flux и мой App.js имеет состояние и прислушивается к изменениям, но я не знаю, как передать это состояние до this.props.children. Перед использованием response-router мой App.js явно определяет всех детей, поэтому состояние передачи было естественным, но я не вижу, как это сделать сейчас.

+1

Возможный дубликат [Как передать реквизит {this.props.children}] (http://stackoverflow.com/questions/32370994/how-to-pass-props-to-this-props- дети) –

ответ

27

Используя пару Реагировать вспомогательные методы, которые можно добавить состояние, реквизит и все остальное, чтобы 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> 
} 

Тогда ваш ребенок компонент может получить доступ к этому с помощью реквизита, this.props.foo.

+0

Да, я читал о помощнике детей и видел это. Зачем использовать Map, а не ForEach? – Patrick

+1

Обычно рекомендуется не мутировать данные, если вы можете им помочь. Это хорошая практика программирования в целом, а не только для React. Только делайте мутации, если нет другого возможного решения - это редкий случай. – azium

+0

Я согласен с мутациями, но, я думаю, я не вижу связи - действительно ли ForEach обязательно мутирует состояние? – Patrick

10

Для этого вы можете использовать React method "cloneElement". Когда вы клонируете элемент, в это время вы можете пройти в реквизитах. Используйте клон вместо оригинала в рендере fn. например:

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

Отсутствие фигурных скобок вокруг 'childrenWithProps' – azium

+0

Был ли ваш пример клонировать всех детей или только один в том случае, если this.props.children имеет только один элемент? Я видел другой пример в stackoverflow, но мне показалось неправильным, что мне нужно будет вручную перебирать их, чтобы пропустить базовые реквизиты. – Patrick

+1

@Patrick Если вы посмотрите на мой ответ, вы сначала заметите «Дети.map». Это необходимо, как правило, потому что 'children' может быть объектом или массивом, а в последнем случае вы клонируете каждый элемент. – azium

2

Существует также возможность использования Context. React-Router полагается на это, чтобы предоставить доступ к объекту Router в компонентах маршрута.

С другой answer я дал на аналогичный вопрос:

Я быстро положить вместе пример использования контекстов на 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')) 
Смежные вопросы