react - router-передайте упоры компоненту обработчика
у меня есть следующая структура для моей реакции.JS приложение с помощью Реагировать-Маршрутизатор:
var Dashboard = require('./Dashboard');
var Comments = require('./Comments');
var Index = React.createClass({
render: function () {
return (
<div>
<header>Some header</header>
<RouteHandler />
</div>
);
}
});
var routes = (
<Route path="/" handler={Index}>
<Route path="comments" handler={Comments}/>
<DefaultRoute handler={Dashboard}/>
</Route>
);
ReactRouter.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
Я хочу передать некоторые свойства в Comments
компонент.
(обычно я бы сделал это как <Comments myprop="value" />
)
каков самый простой и правильный способ сделать это с помощью React Router?
20 ответов
обновление С новой версии можно передавать реквизит непосредственно через Route
компонент, без использования обертки
например, с помощью render
проп. Ссылка на маршрутизатор react:https://reacttraining.com/react-router/web/api/Route/render-func
пример кода в codesandbox:https://codesandbox.io/s/z3ovqpmp44
компонент
class Greeting extends React.Component {
render() {
const { text, match: { params } } = this.props;
const { name } = params;
return (
<React.Fragment>
<h1>Greeting page</h1>
<p>
{text} {name}
</p>
</React.Fragment>
);
}
}
и использование
<Route path="/greeting/:name" render={(props) => <Greeting text="Hello, " {...props} />} />
СТАРАЯ ВЕРСИЯ
мой предпочтительный способ-обернуть Comments
component и передать оболочку в качестве обработчика маршрута.
это ваш пример с изменениями применяется:
var Dashboard = require('./Dashboard');
var Comments = require('./Comments');
var CommentsWrapper = React.createClass({
render: function () {
return (
<Comments myprop="myvalue" />
);
}
});
var Index = React.createClass({
render: function () {
return (
<div>
<header>Some header</header>
<RouteHandler />
</div>
);
}
});
var routes = (
<Route path="/" handler={Index}>
<Route path="comments" handler={CommentsWrapper}/>
<DefaultRoute handler={Dashboard}/>
</Route>
);
ReactRouter.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
Если вы не хотите писать обертки, я думаю, вы могли бы сделать это:
class Index extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<h1>
Index - {this.props.route.foo}
</h1>
);
}
}
var routes = (
<Route path="/" foo="bar" component={Index}/>
);
копирование с комментариями ciantic в принятом ответ:
<Route path="comments" component={() => (<Comments myProp="value" />)}/>
Это самое изящное решение на мой взгляд. Это работает. Помочь мне.
это решение от Раджеш, без неудобных прокомментировал Юджи, и обновлено для React Router 4.
код будет выглядеть так:
<Route path="comments" render={(props) => <Comments myProp="value" {...props}/>}/>
обратите внимание, что я использую render
вместо component
. Причина в том, чтобы избежать нежелательные перемонтирование. Я также передаю props
к этому методу, и я использую те же реквизиты в компоненте комментариев с оператором распространения объекта (предложение ES7).
просто продолжение ответа Колха. Довольно легко абстрагировать обертывание компонента:
var React = require('react');
var wrapComponent = function(Component, props) {
return React.createClass({
render: function() {
return React.createElement(Component, props);
}
});
};
<Route path="comments" handler={wrapComponent(Comments, {myprop: value})}/>
Я еще не тестировал это решение, поэтому важна любая обратная связь.
важно отметить, что с помощью этого метода любые реквизиты, отправленные через маршрутизатор (например, params), перезаписываются / удаляются.
вы можете передать реквизит, передавая их в <RouteHandler>
(в v0.13.x) или сам компонент маршрута в v1.0;
// v0.13.x
<RouteHandler/>
<RouteHandler someExtraProp={something}/>
// v1.0
{this.props.children}
{React.cloneElement(this.props.children, {someExtraProp: something })}
(из руководства по обновлению в https://github.com/rackt/react-router/releases/tag/v1.0.0)
все обработчики ребенок получит тот же набор реквизита - это может быть полезно или нет в зависимости от обстоятельств.
используя ES6, вы можете просто сделать обертки компонентов встроенными:
<Route path="/" component={() => <App myProp={someValue}/>} >
Если вам нужно пройти детей:
<Route path="/" component={(props) => <App myProp={someValue}>{props.children}</App>} >
React-маршрутизатор v4 Альфа
теперь есть новый способ, чтобы сделать это, хотя очень похож на предыдущий метод.
import { Match, Link, Miss } from 'react-router';
import Homepage from './containers/Homepage';
const route = {
exactly: true,
pattern: '/',
title: `${siteTitle} - homepage`,
component: Homepage
}
<Match { ...route } render={(props) => <route.component {...props} />} />
P. S. Это работает только в альфа-версии, и были удалены после альфа-версии V4. В V4 последний, еще раз, с путем и точным реквизитом.
реагировать-lego пример приложение содержит код, который делает именно это в маршрутах.js на ветке react-router-4
вот самое чистое решение, которое я придумал (React Router v4):
<Route
path="/"
component={props => <MyComponent {...props} foo="lol" />}
/>
MyComponent
еще props.match
и props.location
и props.foo === "lol"
.
вы также можете использовать routehandler mixin, чтобы избежать компонента обертки и более легко передать состояние родителя как реквизит:
var Dashboard = require('./Dashboard');
var Comments = require('./Comments');
var RouteHandler = require('react-router/modules/mixins/RouteHandler');
var Index = React.createClass({
mixins: [RouteHandler],
render: function () {
var handler = this.getRouteHandler({ myProp: 'value'});
return (
<div>
<header>Some header</header>
{handler}
</div>
);
}
});
var routes = (
<Route path="/" handler={Index}>
<Route path="comments" handler={Comments}/>
<DefaultRoute handler={Dashboard}/>
</Route>
);
ReactRouter.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
вы можете пройти в реквизит через <RouterHandler/>
такой:
var Dashboard = require('./Dashboard');
var Comments = require('./Comments');
var Index = React.createClass({
render: function () {
var props = this.props; // or possibly this.state
return (
<div>
<header>Some header</header>
<RouteHandler {...props} />
</div>
);
}
});
недостатком это вы передаете реквизит огульно. Так что Comments
может в конечном итоге получить реквизиты, которые действительно предназначены для другого компонента в зависимости от конфигурации маршрутов. Это не большое дело, так как props
является неизменяемым, но это может быть проблематично, если два разных компонента ожидают prop с именем foo
но с разными значениями.
оберните его компонентом функции без состояния:
<Router>
<Route
path='/'
component={({children}) =>
<MyComponent myProp={'myVal'}>{children}</MyComponent/>
}/>
</Router>
В 1.0 и 2.0 вы можете использовать createElement
опора Router
, чтобы указать, как именно создать свой целевой элемент. источник документации
function createWithDefaultProps(Component, props) {
return <Component {...props} myprop="value" />;
}
// and then
<Router createElement={createWithDefaultProps}>
...
</Router>
вы также можете объединить es6 и функции без гражданства чтобы получить гораздо более чистый результат:
import Dashboard from './Dashboard';
import Comments from './Comments';
let dashboardWrapper = () => <Dashboard {...props} />,
commentsWrapper = () => <Comments {...props} />,
index = () => <div>
<header>Some header</header>
<RouteHandler />
{this.props.children}
</div>;
routes = {
component: index,
path: '/',
childRoutes: [
{
path: 'comments',
component: dashboardWrapper
}, {
path: 'dashboard',
component: commentsWrapper
}
]
}
для маршрутизатора react 2.x.
const WrappedComponent = (Container, propsToPass, { children }) => <Container {...propsToPass}>{children}</Container>;
и в ваши маршруты...
<Route path="/" component={WrappedComponent.bind(null, LayoutContainer, { someProp })}>
</Route>
убедитесь, что 3-й param является объектом, как:{ checked: false }
.
React Router v 4 решение
я наткнулся на этот вопрос сегодня, а вот шаблон, который я использую. Надеюсь, это полезно для тех, кто ищет более современное решение.
Я не уверен, что это лучшие решение, но это мой текущий шаблон для этого. Обычно у меня есть основной каталог, где я храню свои часто используемые компоненты с их соответствующими конфигурациями (загрузчики, модалы и т. д.), И я включаю файл вот так:
import React from 'react'
import { Route } from 'react-router-dom'
const getLocationAwareComponent = (component) => (props) => (
<Route render={(routeProps) => React.createElement(component,
{...routeProps, ...props})}/>
)
export default getLocationAwareComponent
затем в рассматриваемом файле я сделаю следующее:
import React from 'react'
import someComponent from 'components/SomeComponent'
import { getLocationAwareComponent } from 'components/Core/getLocationAwareComponent'
const SomeComponent = getLocationAwareComponent(someComponent)
// in render method:
<SomeComponent someProp={value} />
вы заметите, что я импортирую экспорт по умолчанию моего компонента как humble camel-case, что позволяет мне назвать новый компонент с учетом местоположения в CamelCase, чтобы я мог использовать его нормально. Помимо дополнительной строки импорта и строки назначения, компонент ведет себя так, как ожидалось, и получает все свои реквизиты нормально, с добавлением всех реквизитов маршрута. Таким образом, я могу с радостью перенаправить из методов жизненного цикла компонента с этим.реквизит.история.нажмите (), проверьте местоположение и т. д.
надеюсь, что это помогает!
проблема с маршрутизатором React заключается в том, что он отображает ваши компоненты и поэтому останавливает вас в props. The навигация маршрутизатор, С другой стороны, позволяет отображать собственные компоненты. Это означает, что вам не нужно прыгать через какие-либо обручи, чтобы пройти в реквизит как следующий код и сопровождающий JsFiddle показать.
var Comments = ({myProp}) => <div>{myProp}</div>;
var stateNavigator = new Navigation.StateNavigator([
{key:'comments', route:''}
]);
stateNavigator.states.comments.navigated = function(data) {
ReactDOM.render(
<Comments myProp="value" />,
document.getElementById('content')
);
}
stateNavigator.start();
используйте компонент с маршрутизатором или без него на основе ответа Rajesh Naroth.
class Index extends React.Component {
constructor(props) {
super(props);
}
render() {
const foo = (this.props.route) ? this.props.route.foo : this.props.foo;
return (
<h1>
Index - {foo}
</h1>
);
}
}
var routes = (
<Route path="/" foo="bar" component={Index}/>
);
или можно сделать это так:
export const Index = ({foo, route}) => {
const content = (foo) ? foo : (route) ? route.foo : 'No content found!';
return <h1>{content}</h1>
};
для react-router 2.5.2 решение настолько простое:
//someConponent
...
render:function(){
return (
<h1>This is the parent component who pass the prop to this.props.children</h1>
{this.props.children && React.cloneElement(this.props.children,{myProp:'value'})}
)
}
...
С помощью пользовательский компонент маршруту, это возможно в React Router v3.
var Dashboard = require('./Dashboard');
var Comments = require('./Comments');
var routes = (
<Route path="/" handler={Index}>
<MyRoute myprop="value" path="comments" handler={Comments}/>
<DefaultRoute handler={Dashboard}/>
</Route>
);
что касается <MyRoute>
код компонента, это должно быть что-то вроде:
import React from 'react';
import { Route } from 'react-router';
import { createRoutesFromReactChildren } from 'react-router/lib//RouteUtils';
const MyRoute = () => <div><MyRoute> elements are for configuration only and should not be rendered</div>;
MyRoute.createRouteFromReactElement = (element, parentRoute) => {
const { path, myprop } = element.props;
// dynamically add crud route
const myRoute = createRoutesFromReactChildren(
<Route path={path} />,
parentRoute
)[0];
// higher-order component to pass myprop as resource to components
myRoute.component = ({ children }) => (
<div>
{React.Children.map(children, child => React.cloneElement(child, { myprop }))}
</div>
);
return myRoute;
};
export default MyRoute;
для получения более подробной информации о пользовательских компонентов подступом, проверить мой блог на эту тему: http://marmelab.com/blog/2016/09/20/custom-react-router-component.html