React Router を使用して、私のReact.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で最も簡単で正しい方法は何ですか?
新しいリリース以降、Wrapperを使用せずにRoute
コンポーネントを介して直接propsを渡すことが可能になりました。たとえば、 でrender
prop を使用する。
コンポーネント:
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
コンポーネントをラップしてラッパーをルートハンドラとして渡すことです。
これは、変更が適用された例です。
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" />)}/>
これは私の考えでは最も優雅な解決策です。できます。助けて頂きました。
これは Rajeshのソリューション で、不便な{ yujiによるコメント を除いたもので、React Router 4用に更新されたものです。
コードは次のようになります。
<Route path="comments" render={(props) => <Comments myProp="value" {...props}/>}/>
render
の代わりにcomponent
を使用していることに注意してください。その理由は 望ましくない再マウント を避けるためです。私はまたそのメソッドにprops
を渡します、そして、私はコメントコンポーネントの上で同じ広がりをオブジェクト広がり演算子と共に使います(ES7提案)。
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})}/>
私はまだこの解決策をテストしていないので、どんなフィードバックでも重要です。
この方法では、Router経由で送信された小道具(paramsなど)は上書きまたは削除されることに注意することが重要です。
あなたはそれらを<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 から)
すべての子ハンドラは同じ小道具セットを受け取ります - これは役に立つかもしれませんし、状況によっては違います。
ES6を使用すると、コンポーネントラッパーをインラインにすることができます。
<Route path="/" component={() => <App myProp={someValue}/>} >
あなたが子供を渡す必要があるならば:
<Route path="/" component={(props) => <App myProp={someValue}>{props.children}</App>} >
以前の方法と非常によく似ていますが、今、これを行うための新しい方法があります。
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最新版では、パスと正確な小道具が再び使用されています。
react-lego サンプルアプリには、まさにこれを行うコードが含まれています - react-router-4ブランチのroutes.jsに
これが私が思いついた最もきれいな解決策です(React Router v4):
<Route
path="/"
component={props => <MyComponent {...props} foo="lol" />}
/>
MyComponent
にはまだprops.match
とprops.location
があり、props.foo === "lol"
があります。
それをステートレス関数コンポーネントでラップします。
<Router>
<Route
path='/'
component={({children}) =>
<MyComponent myProp={'myVal'}>{children}</MyComponent/>
}/>
</Router>
このように<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
は不変なので大したことではありませんが、2つの異なるコンポーネントがfoo
という名前のプロップを期待しているが値が異なる場合、これは問題になる可能性があります。
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);
});
1.0と2.0では、createElement
のRouter
propを使用して、ターゲット要素の作成方法を正確に指定できます。 ドキュメンテーションソース
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
}
]
}
反応ルータ2.x用。
const WrappedComponent = (Container, propsToPass, { children }) => <Container {...propsToPass}>{children}</Container>;
そしてあなたのルートで...
<Route path="/" component={WrappedComponent.bind(null, LayoutContainer, { someProp })}>
</Route>
3番目のパラメータが{ checked: false }
のようなオブジェクトであることを確認してください。
React Router v 4のソリューション
私は本日早くこの質問につまずいた、そしてこれが私が使うパターンだ。うまくいけば、これはより最新の解決策を探している人には便利です。
これが best ソリューションであるかどうかはわかりませんが、これが私の現在のパターンです。私はよく使用するコンポーネントをそれらに関連する設定(ローダー、モーダルなど)で保管する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} />
あなたは私のコンポーネントのデフォルトのエクスポートを控え目なキャメルケースとしてインポートしていることに気付くでしょう。追加のインポート行と割り当て行を除いて、コンポーネントは期待どおりに動作し、すべてのルートプロップを追加して、すべてのプロップを通常どおり受け取ります。したがって、this.props.history.Push()を使ってコンポーネントのライフサイクルメソッドからリダイレクトしたり、場所を確認したりできます。
お役に立てれば!
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の問題点は、コンポーネントがレンダリングされるため、小道具を渡すのが止まることです。 ナビゲーションルーター は、その一方で、あなた自身のコンポーネントをレンダリングすることができます。つまり、次のコードのように小道具を渡したり、 JsFiddle showを付け加えたりするのにフープを通過する必要はありません。
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();
カスタムルートコンポーネント を使用すると、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
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'})}
)
}
...
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;
これはおそらく、Cookieハンドラでreact-router-domを使用するための最良の方法です。
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}))
}
/>
)
}