Help us understand the problem. What is going on with this article?

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

参考

park-jh
プルスタックエンジニアになれるまで頑張ろう。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした