Response-router - передать реквизиты компоненту обработчика
У меня есть следующая структура для моего приложения React.js, используя React Router:
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?
Ответы
Ответ 1
ОБНОВИТЬ
Начиная с нового выпуска, можно передавать реквизиты напрямую через компонент Route
, без использования Wrapper. Например, с помощью render
проп.
Составная часть:
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} />} />
Пример Codesandbox
СТАРАЯ ВЕРСИЯ
Мой предпочтительный способ - обернуть компонент Comments
и передать обертку как обработчик маршрута.
Это ваш пример с внесенными изменениями:
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);
});
Ответ 2
Если вы предпочитаете не писать обертки, я думаю, вы могли бы сделать это:
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}/>
);
Ответ 3
Копирование комментариев ciantic в принятом ответе:
<Route path="comments" component={() => (<Comments myProp="value" />)}/>
Это самое изящное решение, на мой взгляд. Оно работает. Помог мне.
Ответ 4
Это решение от Rajesh без неудобства прокомментированное yuji, и обновлено для React Router 4.
Код будет выглядеть следующим образом:
<Route path="comments" render={(props) => <Comments myProp="value" {...props}/>}/>
Обратите внимание, что вместо component
я использую render
. Причина заключается в том, чтобы избежать нежелательного повторного подключения. Я также передаю props
этому методу, и я использую те же реквизиты компонента Комментарии с оператором распространения объектов (предложение ES7).
Ответ 5
Просто ответьте на вопрос ColCh. Очень легко абстрагировать обертку компонента:
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})}/>
Я еще не тестировал это решение, поэтому важна любая обратная связь.
Важно отметить, что с помощью этого метода любые реквизиты, отправленные через маршрутизатор (такие как параметры), перезаписываются/удаляются.
Ответ 6
Вы можете передать реквизиты, передав их <RouteHandler>
(в v0.13.x) или самому компоненту Route в версии 1.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)
Все дочерние обработчики получат тот же набор реквизитов - это может быть полезно или не зависит от обстоятельств.
Ответ 7
Используя ES6, вы можете просто сделать обертки компонентов inline:
<Route path="/" component={() => <App myProp={someValue}/>} >
Если вам нужно пройти детей:
<Route path="/" component={(props) => <App myProp={someValue}>{props.children}</App>} >
Ответ 8
React-router v4 alpha
теперь есть новый способ сделать это, хотя он очень похож на предыдущий метод.
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 alpha. В последней версии v4, опять же, путь и точные реквизиты.
react-lego примерное приложение содержит код, который выполняет именно этот в routes.js на ветке ответ-маршрутизатор-4
Ответ 9
Здесь самое чистое решение, с которым я столкнулся (React Router v4):
<Route
path="/"
component={props => <MyComponent {...props} foo="lol" />}
/>
MyComponent
все еще имеет props.match
и props.location
и имеет props.foo === "lol"
.
Ответ 10
Вы также можете использовать Mixing RouteHandler, чтобы избежать компонента-оболочки и более легко передать родительское состояние в качестве реквизита:
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);
});
Ответ 11
Вы можете передать реквизит через <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
неизменяема, но это может быть проблематично, если две разные компоненты ожидают прозвище с именем foo
, но с разными значениями.
Ответ 12
Оберните его компонентом функции без состояния:
<Router>
<Route
path='/'
component={({children}) =>
<MyComponent myProp={'myVal'}>{children}</MyComponent/>
}/>
</Router>
Ответ 13
В 1.0 и 2.0 вы можете использовать createElement
prop Router
, чтобы указать, как именно создать ваш целевой элемент. Источник документации
function createWithDefaultProps(Component, props) {
return <Component {...props} myprop="value" />;
}
// and then
<Router createElement={createWithDefaultProps}>
...
</Router>
Ответ 14
Вы также можете комбинировать 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
}
]
}
Ответ 15
Для ответного маршрутизатора 2.x.
const WrappedComponent = (Container, propsToPass, { children }) => <Container {...propsToPass}>{children}</Container>;
и на ваших маршрутах...
<Route path="/" component={WrappedComponent.bind(null, LayoutContainer, { someProp })}>
</Route>
убедитесь, что третий параметр - это объект: { checked: false }
.
Ответ 16
Решение React Router v 4
Я наткнулся на этот вопрос ранее сегодня, и вот шаблон, который я использую. Надеюсь, это полезно для всех, кто ищет более актуальное решение.
Я не уверен, что это лучшее решение, но это мой текущий шаблон для этого. Обычно у меня есть каталог Core, где я храню свои часто используемые компоненты с их соответствующими конфигурациями (загрузчики, модалы и т.д.), И я включаю такой файл:
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} />
Вы заметите, что я импортирую экспорт по умолчанию моего компонента в качестве скромного верблюжьего футляра, который позволяет мне назвать новый компонент, ориентированный на местоположение, в CamelCase, поэтому я могу использовать его в обычном режиме. Помимо дополнительной линии импорта и линии назначения, компонент ведет себя как ожидалось и обычно получает все свои реквизиты с добавлением всех реквизитов маршрута. Таким образом, я могу с радостью переадресовать из методов жизненного цикла компонента с помощью this.props.history.push(), проверить местоположение и т.д.
Надеюсь, это поможет!
Ответ 17
Проблема с React Router заключается в том, что он отображает ваши компоненты и поэтому останавливает вас в реквизитах. С другой стороны, навигационный маршрутизатор позволяет создавать собственные компоненты. Это означает, что вам не нужно прыгать через любые обручи, чтобы пройти в реквизитах, как показано в следующем коде и сопутствующих 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();
Ответ 18
Используйте компонент с маршрутизатором или без него на основе ответа Раджеша Нарота.
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>
};
Ответ 19
для реактивного маршрутизатора 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'})}
)
}
...
Ответ 20
Используя настраиваемый компонент маршрута, это возможно в 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
Ответ 21
это, вероятно, лучший способ использования response-router-dom с обработчиком файлов cookie
в index.js
import React, { Component } from 'react'
import {Switch,Route,Redirect} from "react-router-dom"
import {RouteWithLayout} from "./cookieCheck"
import Login from "../app/pages/login"
import DummyLayout from "../app/layouts/dummy"
import DummyPage from "../app/pages/dummy"
export default ({props})=>{
return(
<Switch>
<Route path="/login" component={Login} />
<RouteWithLayout path="/dummy" layout={DummyLayout} component={DummyPage}
{...props}/>
<Redirect from="/*" to="/login" />
</Switch>
)
}
и используйте cookieCheck
import React , {createElement} from 'react'
import {Route,Redirect} from "react-router-dom"
import {COOKIE,getCookie} from "../services/"
export const RouteWithLayout = ({layout,component,...rest})=>{
if(getCookie(COOKIE)==null)return <Redirect to="/login"/>
return (
<Route {...rest} render={(props) =>
createElement(layout, {...props, ...rest}, createElement(component,
{...props, ...rest}))
}
/>
)
}
Ответ 22
class App extends Component {
constructor(props){
super(props);
this.state = {
data:null
}
}
componentDidMount(){
database.ref().on('value', (snapshot) =>{
this.setState({
data : snapshot.val()
})
});
}
render(){
// const { data } = this.state
return (
<BrowserRouter>
<Switch>
<Route exact path = "/" component = { LandingPage } />
<Route
path='/signup'
render = { () => <Signup data = {this.state.data} />} />
</Switch>
</BrowserRouter>
);
}
};
export default App;