33
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-08-04

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"が表示される。

参考

33
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?