Edited at

react-router v4にてchild componentにpropsを渡す方法

More than 1 year has passed since last update.

react-router v4にてchild componentにpropsを渡す方法には2つがある。


  • render propsを使う。

  • recomposeでhigher order component(HOC)を作る。


render propsを使う。

Routeをレンダリングする方法には3つがある。


  • <Route component>

  • <Route render>

  • <Route children>

マッチされたurlに対して、指定されたcomponentをレンダリングするのがRoute componentである。

Route renderはinlineで指定されたのをレンダリングする。

Route componentとは違ってレンダリングの対象にpropertyを指定して渡すのができる。

ここではRoute renderを用いてchild componentにpropertyを渡してみよう。(Route childrenについては割愛する。)

次の記事にあるソースコードをそのまま使って直した。


src/components/routing/Main.js

--- a/src/components/routing/Main.js

+++ b/src/components/routing/Main.js
@@ -8,7 +8,7 @@ const Main = () => (
<main>
<Switch>
<Route exact path="/" component={Home} />
- <Route path="/about" component={About} />
+ <Route path="/about" render={() => <About title="About Us" />} />
<Route path="/repos" component={Repos} />
</Switch>
</main>

ここではAboutというpure component(=stateless component)のpropsにtitleを追加して渡してる。


src/components/routing/About.js

--- a/src/components/routing/About.js

+++ b/src/components/routing/About.js
@@ -1,11 +1,16 @@
import React, { Component } from 'react';
+import PropTypes from 'prop-types';

class About extends Component {
render() {
return (
- <h1>About</h1>
+ <h1>{this.props.title}</h1>
);
}
}

+About.propTypes = {
+ title: PropTypes.string.isRequired,
+};
+
export default About;


Aboutリンクをクリックすると、"About"の代わりに"About Us"が表示される。


recomposeでhigher order component(HOC)を作る。


higher order componentとは

higher orderは「上位」又は「高位」という意味らしい。

既存のcomponentより高位のcomponentという意味で名付けたことではないだろうか。

high order componentは、react componentをレンダリングするfunctionを返すfunctionを言う。

既存のcomponentに新たな機能を追加して再組み立て(recompose)したものだと考えてもいい。

このとき、よく使われるlibraryがrecomposeである。

recomposeのwithPropというmoduleを使えば、既存のcomponentにpropsの追加が容易である。

recomposeにはwithProp以外にもいろんなmoduleが存在する。

ここではwithPropだけを紹介するが、reactにもっと上達になりたい場合はrecomposeのgithubを参照しよう。

さあ、recomposeを設置しよう。

  yarn add recompose

既存のサンプルからpure component(=stateless component)をarrow functionで直してみた。

pure componentの場合は、class式よりfunctionで作るのがもっといい方法らしい。

Building HOCs with Recomposeの記事になぜpure componentはfunctionで作るべきなのかについて書かれていたので紹介する。


Modular code : Reusable pieces that can plug in across your site

Reliance on a props-only interface : Stateless interface by default

Easily Unit Tested : Easily test interface with enzyme/jest

Easily Mocked : Easily mock props for different situations


pure componentはstatelessなviewのpieceでサイト内いろんなところに跨って使われる。

そして、テストコードやmockを作る場合、functionのほうがもっと容易である。

コードを組むときはテストしやすい形で組むのが正しい。


src/components/routing/About.js

--- a/src/components/routing/About.js

+++ b/src/components/routing/About.js
@@ -1,13 +1,9 @@
-import React, { Component } from 'react';
+import React from 'react';
import PropTypes from 'prop-types';

-class About extends Component {
- render() {
- return (
- <h1>{this.props.title}</h1>
- );
- }
-}
+const About = props => (
+ <h1>{props.title}</h1>
+);

About.propTypes = {
title: PropTypes.string.isRequired,



src/components/routing/Home.js

--- a/src/components/routing/Home.js

+++ b/src/components/routing/Home.js
@@ -1,11 +1,7 @@
-import React, { Component } from 'react';
+import React from 'react';

-class Home extends Component {
- render() {
- return (
- <h1>HOME</h1>
- );
- }
-}
+const Home = () => (
+ <h1>HOME</h1>
+);

export default Home;

次が肝心のところだ。

recomposeのwithPropsを用いてAbout componentを再組み立て(recompose)する。

Aboutのpropsにtitleを追加し、AboutをラップしたAboutWithTitleを作った。


src/components/routing/Main.js

--- a/src/components/routing/Main.js

+++ b/src/components/routing/Main.js
@@ -1,17 +1,26 @@
import React from 'react';
import { Switch, Route } from 'react-router-dom';
+import withProps from 'recompose/withProps';
import About from './About';
import Home from './Home';
import Repos from './Repos';

-const Main = () => (
- <main>
- <Switch>
- <Route exact path="/" component={Home} />
- <Route path="/about" render={() => <About title="About Us" />} />
- <Route path="/repos" component={Repos} />
- </Switch>
- </main>
-);
+const Main = () => {
+ const AboutWithTitle = withProps(
+ props => ({
+ ...props,
+ title: 'About Us',
+ }),
+ )(About);
+ return (
+ <main>
+ <Switch>
+ <Route exact path="/" component={Home} />
+ <Route path="/about" component={AboutWithTitle} />
+ <Route path="/repos" component={Repos} />
+ </Switch>
+ </main>
+ );
+};

export default Main;


これでAbout componentにtitle propertyが注入された。

Aboutリンクをクリックすると、"About"の代わりに"About Us"が表示される。


参考