web-dev-qa-db-ja.com

react-router - ハンドラコンポーネントにプロップを渡す

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で最も簡単で正しい方法は何ですか?

282
Kosmetika

更新

新しいリリース以降、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} />} />

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);
});
128
ColCh

ラッパーを書かないのであれば、私はあなたがこれを行うことができると思います:

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}/>
);
255
Thomas E

承認された回答の ciantic によるコメントからのコピー:

<Route path="comments" component={() => (<Comments myProp="value" />)}/>

これは私の考えでは最も優雅な解決策です。できます。助けて頂きました。

111
Rajesh Naroth

これは Rajeshのソリューション で、不便な{ yujiによるコメント を除いたもので、React Router 4用に更新されたものです。

コードは次のようになります。

<Route path="comments" render={(props) => <Comments myProp="value" {...props}/>}/>

renderの代わりにcomponentを使用していることに注意してください。その理由は 望ましくない再マウント を避けるためです。私はまたそのメソッドにpropsを渡します、そして、私はコメントコンポーネントの上で同じ広がりをオブジェクト広がり演算子と共に使います(ES7提案)。

52
Daniel Reina

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など)は上書きまたは削除されることに注意することが重要です。

43
sigmus

あなたはそれらを<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 から)

すべての子ハンドラは同じ小道具セットを受け取ります - これは役に立つかもしれませんし、状況によっては違います。

30
cachvico

ES6を使用すると、コンポーネントラッパーをインラインにすることができます。

<Route path="/" component={() => <App myProp={someValue}/>} >

あなたが子供を渡す必要があるならば:

<Route path="/" component={(props) => <App myProp={someValue}>{props.children}</App>} >

23
Nick

React-router 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最新版では、パスと正確な小道具が再び使用されています。

react-lego サンプルアプリには、まさにこれを行うコードが含まれています - react-router-4ブランチのroutes.jsに

22
peter.mouland

これが私が思いついた最もきれいな解決策です(React Router v4):

<Route
  path="/"
  component={props => <MyComponent {...props} foo="lol" />}
/>

MyComponentにはまだprops.matchprops.locationがあり、props.foo === "lol"があります。

19
cgenco

それをステートレス関数コンポーネントでラップします。

<Router>
  <Route 
    path='/' 
    component={({children}) => 
      <MyComponent myProp={'myVal'}>{children}</MyComponent/>
    }/>
</Router>
11
mg74

このように<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という名前のプロップを期待しているが値が異なる場合、これは問題になる可能性があります。

11
Meistro

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
jul

1.0と2.0では、createElementRouter propを使用して、ターゲット要素の作成方法を正確に指定できます。 ドキュメンテーションソース

function createWithDefaultProps(Component, props) {
    return <Component {...props} myprop="value" />;
}

// and then    
<Router createElement={createWithDefaultProps}>
    ...
</Router>
9
Andrew Khmylov

また、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
      }
    ]
}
5
Zhiwei Huang

反応ルータ2.x用。

const WrappedComponent = (Container, propsToPass, { children }) => <Container {...propsToPass}>{children}</Container>;

そしてあなたのルートで...

<Route path="/" component={WrappedComponent.bind(null, LayoutContainer, { someProp })}>
</Route>

3番目のパラメータが{ checked: false }のようなオブジェクトであることを確認してください。

4
holyxiaoxin

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()を使ってコンポーネントのライフサイクルメソッドからリダイレクトしたり、場所を確認したりできます。

お役に立てれば!

4
Chris

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>
};
1
Michael Hobbs

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();
1
graham mendick

カスタムルートコンポーネント を使用すると、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>&lt;MyRoute&gt; 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

0

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'})}
  )
}
...
0
min may
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;
0
nik.ss

これはおそらく、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}))
       }
      />
    )
}
0
Snivio