- 投稿日:2020-01-07T20:43:37+09:00
まだ相対パスで消耗してるの?
タイトル、煽りでスイマセン。
今回は↓これ↓の話です。
hoge.jsimport SomeComponent from ../../../components/hoge/fuga相対パスのimportです。
"../../"の数がいちいちわからなくなるのって私だけですかね?
また、ファイルを別のフォルダに打ちしたときなんかにエラーが出ることもあったりして、
相対パス、書き換えるの面倒くさいですよね。今回はそんな悩みを絶対パスにして解決してしまおうという記事です。
題して、「絶対パスでReactを書こう!」
(よく考えたら題してないな)内容に間違い等がございましたら、ご意見・ご指摘のほど宜しくお願いいたします。
前提:やり方は意外に簡単だよ!という話
調べたら色んなやり方が出てきましたが、一番手っ取り早い方法をご紹介します。
以下は概要。
- webpack.config.jsonは使いません。
- .babelrcは作りません。
- ts.config.jsonを使います。
- typescriptじゃなくてもOKです。
素のjavascirpt(typescriptじゃないという意味で素)でもts.config.jsonが使えるというのは、私も今回初めて知りました。
以下の記事が大変参考になったので貼っておきます。感謝!
https://qiita.com/terrierscript/items/a9826bc58d550d1b2764
また公式ドキュメントも先に貼っておきますのでお急ぎの方はこちらをご参照ください。
https://create-react-app.dev/docs/importing-a-component/#absolute-importsでは早速、方法をご紹介していきます。
step① tsconfig.jsonを作る
プロジェクトのroot(package.jsonなどがある場所)にts.config.jsonを作成します。
npx typescript --initして下記のように設定してください。
(下記はhttps://create-react-app.dev/より引用。)tsconfig.json{ "compilerOptions": { "baseUrl": "src" }, "include": ["src"] }自分は下記のように設定を加えています。
tsconfig.json{ "compilerOptions": { "incremental": true, "target": "es5", "module": "esnext", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "jsx": "react", "isolatedModules": true, "strict": true, "baseUrl": "src", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true, "allowSyntheticDefaultImports": true, "moduleResolution": "node", "resolveJsonModule": true, "noEmit": true }, "include": ["src"], "exclude": ["node_modules", "build", "scripts", "functions"] }なおts.config.jsonの書き方については、下記を参考にさせていただきました。
https://usefuledge.com/pb_00009_tscconfig_json.html
自分はこの辺りの設定にあまり詳しくないので、「ここがおかしい」とか「こうした方がいいよ」というのがございましたら、ぜひぜひコメント欄にお願いいたします。ちなみに"allowJs": true”というやーつは、名前の通り「TypeScriptやなくても許してやりまっか〜」という意味なので、JSに段階的にTSを導入していきたい方は加えておくといいかもしれません。
step② TypeScriptを入れる
素のJSでtsconfig.jsonを作成すると、TypeScriptじゃないのにtsconfigがあるよ!
というような趣旨のエラーがでるので、その案内に従ってTypeScriptを入れてください。
具体的に書くと、
”It looks like you're trying to use TypeScript but do not have typescript installed.Please install typescript by running yarn add typescript”
とお叱りを受けるので、npm install --save-dev typescriptでおkということです。
とはいえ、拡張子をtsxにしたり、全部anyにして無理やりTypeScript化する必要はありません。
ただインストールするだけです。
(ts入れて使わないならjsconfig.jsonで良くね?という話は冒頭でご紹介した記事を御覧ください。)結果:絶対パスで書けるようになる
例
hoge.jsimport AbsoluteImportComponent from components/hoge/fuga import RelativeImportComponent from ../components/hoge/hoge絶対パスで書けるようになります!意外と簡単でしたね。
絶対パスでしか書けなくなるのではなく、どうやら両方いけるみたいです。まとめ
絶対パスを使うとimportがむっちゃすっきりするよ、という話でした。
最後まで読んでいただいてありがとうございました!
- 投稿日:2020-01-07T19:11:19+09:00
Reduxの学習に躊躇うReact初級者に送る話
Reduxつらい問題ってありますよね。
ちょっとした実装がしたいだけなのに、Reduxだとボイラーテンプレートが多くてやたら量を書かないといけなかったりする。
「action? dispatch? reducer? 色々と学ぶことが多くて大変そう」と思う方もいらっしゃるでしょう。
今回はそんなReduxに尻込みしているReact初級者の方に送るReduxの話です。メリット① ReduxDevTools便利すぎ
あなたがもし、Reactを書くためにいろんなところにConsole.logをしかけて、挙動を確認しているとしたら、ReduxDevToolsはそんなあなたの手間を劇的に削減することでしょう
ReduxDevToolsを使うためにReduxを書いているといっても過言ではありません。
いやさすがにそれは言い過ぎました。(どっちやねん!)
何はともあれ、ReduxDevToolsは非常に便利ですのでReduxを使ってみましょうメリット② 大きめのプロジェクトを管理しやすい
あなたはこう言うでしょう。
「簡単なことがしたいだけなのに!10行で書けることがReduxだと30行にも40行にもなる!」
その気持ちぐぅわかるよ。。。
Reduxのメリットは、大きめのプログラムでReduxを使ったことがある人にしかわからないものです。そうReduxは大きくなればなるほどその力を発揮するものであって、
個人で開発するWebアプリにとってはほぼ例外なくオーバーキルです。
しかし、いざ大規模の開発となるとReduxは輝きます。
そのときに向けて個人開発で予行演習しておくことを強く推します。メリット③ 綺麗なコードについて考えるようになる
②とも共通することですが、Reduxで書くとそうでないときより読みやすくなることが多いです。
なぜなら、Reduxというのは単に状態管理のライブラリではなく、コードを体系的に書くための1個の考え方でもあるからです。(あくまで個人的な意見ですが。)
Reduxを勉強する過程で、綺麗なコードを書くための先人たちの知恵や思想に数多く出会うことでしょう。
それはducksかもしれないし、re-ducksかもしれないし、presentational-componentsとfunctional-componentsを分離させることかもしれません。
それが何であれ、その考え方自体は、いつかReduxが別のライブラリにとって代わられたとしても、一個に思想として残り続ける価値のあるものであるだと思います。もし「immutableってどういうことだ?」「ディレクトリ構成ってどうやったらいんだ?」などと考えたことがあるなら、それはReduxを学ぶための最良のチャンスですよ!
余談:HooksもいいけどReduxもいいよ
最後に余談。
Reduxに代わるものとして昨今Hooksに注目が集まっています。
「useContextなら関数も渡せるしReduxみたいな面倒なこともない」とか、
「MobXなどの後発ライブラリを使ったほうが幸せになれる」というような意見もあります。
それでもReduxを推してみたい私です。
理由は、Reduxは必ずしもスマートではないかもしれませんが
やはり数の暴力といいますか、ちゃんとした情報がいろいろ落ちていたり、
Reduxを強力にサポートするツールやライブラリが盛りだくさんだからです。
筆者は個人的にreact-redux-firebaseというreduxとfirebaseを良い感じに併用可能にしてくれるツールが大好きで愛用しています。初心者の方に「大変だけどHooksもReduxも両方学ぶのがベストだよ!」というのが、
今回の結論ということにさせてください!Let's get Started!!
幸いにしてQiitaにはReduxのを学ぶための良記事があるので、まずはそれから始めてはいかがでしょう。
下記にリンクを貼っておきます。
https://qiita.com/mpyw/items/a816c6380219b1d5a3bf
- 投稿日:2020-01-07T19:11:19+09:00
Reduxの学習に躊躇うReact初級者の方に送る話
Reduxつらい問題ってありますよね。
ちょっとした実装がしたいだけなのに、Reduxだとやたら量を書かないといけなかったりする。
「action? dispatch? reducer? 色々と学ぶことが多くて大変そう」と思う方もいらっしゃるでしょう。
今回はそんなReduxに尻込みしているReact初級者の方に送るReduxのメリットについての話です。メリット① ReduxDevTools便利すぎ
Reactを書くときにいろんなところにconsole.logをしかけて、いちいち挙動を確認しているとしたら、ReduxDevToolsはそんなあなたの手間を劇的に削減することでしょう。
ReduxDevToolsを使うためにReduxを書いているといっても過言ではありません。
いやさすがにそれは言い過ぎました。(どっちやねん!)
何はともあれ、ReduxDevToolsは非常に便利ですのでReduxを使ってみましょうメリット② 大きめのプロジェクトを管理しやすい
あなたはこう言うでしょう。
「簡単なことがしたいだけなのに!10行で書けることがReduxだと30行にも40行にもなる!」
その気持ちぐぅわかるよ。。。
Reduxのメリットは、大きめのプログラムでReduxを使ったことがある人にしかわからないものです。そうReduxは大きくなればなるほどその力を発揮するものであって、
個人で開発するWebアプリにとってはほぼ例外なくオーバーキルです。
しかし、いざ大規模の開発となるとReduxは輝きます。
そのときに向けて個人開発で予行演習しておくことを強く推します。メリット③ 綺麗なコードについて考えるようになる
②とも共通することですが、Reduxで書くとそうでないときより読みやすくなることが多いです。
なぜなら、Reduxというのは単に状態管理のライブラリではなく、コードを体系的に書くための1個の考え方でもあるからです。(あくまで個人的な意見ですが。)
Reduxを勉強する過程で、綺麗なコードを書くための先人たちの知恵や思想に数多く出会うことでしょう。
それはducksかもしれないし、re-ducksかもしれないし、presentational-componentsとfunctional-componentsを分離させることかもしれません。
それが何であれ、その考え方自体は、いつかReduxが別のライブラリにとって代わられたとしても、一個に思想として残り続ける価値のあるものであるだと思います。もし「immutableってどういうことだ?」「ディレクトリ構成ってどうやったらいんだ?」などと考えたことがあるなら、それはReduxを学ぶための最良のチャンスですよ!
余談:HooksもいいけどReduxもいいよ
最後に余談。
Reduxに代わるものとして昨今Hooksに注目が集まっています。
「useContextなら関数も渡せるしReduxみたいな面倒なこともない」とか、
「MobXなどの後発ライブラリを使ったほうが幸せになれる」というような意見もあります。
それでもReduxを推してみたい私です。
理由は、Reduxは必ずしもスマートではないかもしれませんが
やはり数の暴力といいますか、ちゃんとした情報がいろいろ落ちていたり、
Reduxを強力にサポートするツールやライブラリが盛りだくさんだからです。
筆者は個人的にreact-redux-firebaseというreduxとfirebaseを良い感じに併用可能にしてくれるツールが大好きで愛用しています。初心者の方に「大変だけどHooksもReduxも両方学ぶのがベストだよ!」というのが、
今回の結論ということにさせてください!Let's get Started!!
幸いにしてQiitaにはReduxのを学ぶための良記事があるので、まずはそれから始めてはいかがでしょう。
下記にリンクを貼っておきます。
https://qiita.com/mpyw/items/a816c6380219b1d5a3bf
- 投稿日:2020-01-07T19:11:19+09:00
Reduxの学習に躊躇う初級者の方に送る話
Reduxつらい問題ってありますよね。
ちょっとした実装がしたいだけなのに、Reduxだとやたら量を書かないといけなかったりする。
「action? dispatch? reducer? 色々と学ぶことが多くて大変そう」と思う方もいらっしゃるでしょう。
今回はそんなReduxに尻込みしている初級者の方に送るReduxのメリットについての話です。メリット① ReduxDevTools便利すぎ
Reactを書くときにいろんなところにconsole.logをしかけて、いちいち挙動を確認しているとしたら、ReduxDevToolsはそんなあなたの手間を劇的に削減することでしょう。
ReduxDevToolsを使うためにReduxを書いているといっても過言ではありません。
いやさすがにそれは言い過ぎました。(どっちやねん!)
何はともあれ、ReduxDevToolsは非常に便利ですのでReduxを使ってみましょうメリット② 大きめのプロジェクトを管理しやすい
あなたはこう言うでしょう。
「簡単なことがしたいだけなのに!10行で書けることがReduxだと30行にも40行にもなる!」
その気持ちぐぅわかるよ。。。
Reduxのメリットは、大きめのプログラムでReduxを使ったことがある人にしかわからないものです。そうReduxは大きくなればなるほどその力を発揮するものであって、
個人で開発するWebアプリにとってはほぼ例外なくオーバーキルです。
しかし、いざ大規模の開発となるとReduxは輝きます。
そのときに向けて個人開発で予行演習しておくことを強く推します。メリット③ 綺麗なコードについて考えるようになる
②とも共通することですが、Reduxで書くとそうでないときより読みやすくなることが多いです。
なぜなら、Reduxというのは単に状態管理のライブラリではなく、コードを体系的に書くための1個の考え方でもあるからです。(あくまで個人的な意見ですが。)
Reduxを勉強する過程で、綺麗なコードを書くための先人たちの知恵や思想に数多く出会うことでしょう。
それはducksかもしれないし、re-ducksかもしれないし、presentational-componentsとfunctional-componentsを分離させることかもしれません。
それが何であれ、その考え方自体は、いつかReduxが別のライブラリにとって代わられたとしても、一個に思想として残り続ける価値のあるものであるだと思います。もし「immutableってどういうことだ?」「ディレクトリ構成ってどうやったらいんだ?」などと考えたことがあるなら、それはReduxを学ぶための最良のチャンスですよ!
余談:HooksもいいけどReduxもいいよ
最後に余談。
Reduxに代わるものとしてReact界隈だと昨今はHooksに注目が集まっています。
「useContextなら関数も渡せるしReduxみたいな面倒なこともない」という意見もあります。
それでもReduxを推してみたい私です。
Reduxは必ずしもスマートではないかもしれませんが、やはり数の暴力といいますか、ちゃんとした情報がいろいろ落ちていたり、Reduxを強力にサポートするツールやライブラリが盛りだくさんだからです。
筆者は個人的にreact-redux-firebaseというreduxとfirebaseを良い感じに併用可能にしてくれるツールが好きで愛用しています。「大変だけどHooksもReduxも両方学ぶのがベストだよ!」というのを今回の結論とさせてください!
Let's get Started!!
幸いにしてQiitaにはReduxのを学ぶための良記事があるので、まずはそれから始めてはいかがでしょう。
下記にリンクを貼っておきます。
https://qiita.com/mpyw/items/a816c6380219b1d5a3bf
- 投稿日:2020-01-07T19:11:19+09:00
Reduxの学習コストに躊躇う初学者の方に伝えたいこと
Reduxつらい問題ってありますよね。
ちょっとした実装がしたいだけなのに、Reduxだとやたら量を書かないといけなかったりする。
「action? dispatch? reducer? 色々と学ぶことが多くて大変そう」と思う方もいらっしゃるでしょう。
今回はそんなReduxに尻込みしている初学者の方に送るReduxのメリットについての話です。メリット① redux-devtools-extention便利すぎ
Reactを書くときにいろんなところにconsole.logをしかけて、いちいち挙動を確認しているとしたら、redux-devtools-extentionはそんなあなたの手間を劇的に削減することでしょう。
redux-devtools-extentionを使うためにReduxを書いているといっても過言ではありません。
いやさすがにそれは言い過ぎました。(どっちやねん!)
何はともあれ、redux-devtoolsは非常に便利ですのでReduxを使ってみましょう
下記の記事をご参照ください。
https://qiita.com/elzup/items/fc24588b2c6bae0834a6メリット② 大きめのプロジェクトを管理しやすい
あなたはこう言うでしょう。
「簡単なことがしたいだけなのに!10行で書けることがReduxだと30行にも40行にもなるよ!」
その気持ち、ぐぅわかるよ。。。
Reduxのメリットは、大きめのプロジェクトでReduxを使ったことがある人にしかわからないものです。そうReduxは大きくなればなるほどその力を発揮するものであって、
個人で開発するWebアプリにとってはほぼ例外なくオーバーキルです。
しかし、いざ大規模の開発となるとReduxは輝きます。
そのときに向けて個人開発で予行演習しておくことを強く推します。メリット③ 綺麗なコードについて考えるようになる
②とも共通することですが、Reduxで書くとそうでないときより読みやすくなることが多いです。
なぜなら、Reduxというのは単に状態管理のライブラリではなく、コードを体系的に書くための1個の考え方でもあるからです。(あくまで個人的な意見ですが。)
Reduxを勉強する過程で、綺麗なコードを書くための先人たちの知恵や思想に数多く出会うことでしょう。
それはducksかもしれないし、re-ducksかもしれないし、presentational-componentsとcontainer-componentsを分離させることかもしれません。
それが何であれ、その考え方自体は、いつかReduxが別のライブラリにとって代わられたとしても、一個の思想として残り続ける価値のあるものだと思います。もし「immutableってどういうことだ?」「ディレクトリ構成ってどうやったらいんだ?」などと考えたことがあるなら、それはReduxを学ぶための最良のチャンスですよ!
余談:HooksもいいけどReduxもいいよ
最後に余談。
Reduxに代わるものとしてReact界隈だと昨今はHooksに注目が集まっています。
「useContextなら関数も渡せるしReduxみたいな面倒なこともない」という意見もあります。
それでもReduxを推してみたい私です。
Reduxは必ずしもスマートではないかもしれませんが、やはり数の暴力といいますか、ちゃんとした情報がいろいろ落ちていたり、Reduxを強力にサポートするツールやライブラリが盛りだくさんだからです。
筆者は個人的にreact-redux-firebaseというreduxとfirebaseを良い感じに併用可能にしてくれるツールが好きで愛用しています。「大変だけどHooksもReduxも両方学ぶのがベストだよ!」というのを今回の結論とさせてください!
Let's get Started!!
幸いにしてQiitaにはReduxのを学ぶための良記事があるので、まずはそれから始めてはいかがでしょう。
下記にリンクを貼っておきます。
https://qiita.com/mpyw/items/a816c6380219b1d5a3bf
- 投稿日:2020-01-07T12:10:39+09:00
Next.jsアプリでページ遷移時にプログレスバー(ページ上部に出るやつ)を出す
なかなかにミニマルなフレームワーク「Next.js」ではデフォルトではプログレスバーを表示しません。
Nuxt.jsなら勝手にやってくれるんだけどな…と思いつつ、ここではNext.jsでの実現方法を書いておきます。超簡単です!必要なもの
以上!
実装方法
まず、当然ですけどnextjs-progressbarをインストールします。
$ yarn add nextjs-progressbar
/pages/_app.js(ない場合は作る)(_app.jsって何、という方はこちらをどうぞ)を編集します。/pages/_app.jsimport React from 'react' import App from 'next/app' import NextNprogress from 'nextjs-progressbar' // ここ! class MyApp extends App { render() { const { Component, pageProps } = this.props return ( <> <NextNprogress /> { /* ここ! */ } <Component {...pageProps} /> </> ) } } export default MyAppここで一旦宣伝です。
宣伝
先日、@svfreerider さんと共にRemote Club|海外移住や海外フリーランスの情報サイトというサービスを出しました!
既に海外移住した人と、これからしたいと考えている人のつながりを作り、より多くの方々が好きなところで生きていけるようになればいいという思いからRemote Clubを作りました。少しでも海外移住に興味のある方、既に移住している方は是非Remote Clubを覗いていっていただけると嬉しいです!
フィードバックも待ってます!
よろしくおねがいします!まとめ
Next.jsでも特に困ることなくプログレスバーを実装できました。
Nuxt.jsだとデフォルトで表示されるし便利、と思ったけど、まぁ必要な人は追加する、というスタンスのほうが自然な気もしました。
遷移先でAPIなどを使って外部からデータを取得する場合は、どうしても遷移に時間がかかり不自然に感じてしまいます(自分は)。
ということで、クライアントでの遷移にはプログレスバー表示したい!というかたは是非どうぞ!ちなみにnextjs-progressbar作者の方の記事はこちらです。詳しく知りたい方は覗いてみてください。
- 投稿日:2020-01-07T00:15:11+09:00
JavaScriptのUIライブラリ ReactでToDoアプリを作成してみました
はじめに
この記事ではJavaScriptのライブラリであるReactを使用して簡単なToDoアプリの実装を行います。
クライアント側のみの実装になります。
Reactのドキュメントやチュートリアル(三目並べ)を一通り行った後の練習になるように書きたいと思います。
環境構築に関しては、create-react-appを使用して作成しています。環境構築に関しては以前書いた記事があります。
もちろん、オレオレな環境でもokです。
Reactについては初心者なので認識の齟齬や到らない点も多々あると思いますが、よろしくお願いします。目次
- 環境準備
- コンポーネントの確認
- ファイル構成
- Reactで保持するデータについて
- 各コンポーネントの解説
- まとめ
1. 環境準備
以下からソースコードを引っ張ってきます。
ソースコード
gitでクローンした場合は、ブランチはtodo-app-pure-cssです。(何かダサい名前なのは目を瞑っておいてください。。。)
動作を確認するために、ブラウザ上で確認できる環境も用意しました。1-1. DockerImageのビルド
docker build --rm -f "react-tutorial/Dockerfile" -t react-tutorial:latest "react-tutorial"1-2. DockerContainerの起動
$ docker run --rm -it -v ${PWD}/app:/home/react-tutorial -p 3000:3000/tcp react-tutorial:latest /bin/bash root@03887209ce2d:/home#1-3. 追加のパッケージをインストール(コンテナの内部で操作してます)
root@03887209ce2d:/home# cd react-tutorial root@03887209ce2d:/home/react-tutorial# yarn install1-4. Reactアプリケーションの起動
root@03887209ce2d:/home/react-tutorial# yarn start1-5. ブラウザで確認
Reactアプリケーションの起動に成功すると、以下のような表示がされます。
Compiled successfully! You can now view react-tutorial in the browser. Local: http://localhost:3000/ On Your Network: http://172.17.0.3:3000/ Note that the development build is not optimized. To create a production build, use yarn build.ブラウザで
http://localhost:3000/を入力して開いてみましょう。
そうすると、下記の様な画面が表示されるはずです。
今回は、この画面をReactで作成していきたいと思います。2. コンポーネントの確認
ReactはUIのパーツをコンポーネントという独立した一つの部品とみなして構成していきます。
今回の例では下記の様に分割しました。ToDoアプリケーションを構成するコンポーネントは全部で4つあります。
ToDo
ToDoアプリケーションの全体を表しますTaskAdd
新しいタスクの追加を行いますTaskList
追加されたタスクをリストにして表示しますTaskItem
一つのタスクを表します3. ファイル構成
ファイル構成を確認しましょう。
フォルダ構成. ├── Dockerfile ├── README.md └── app ├── README.md ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.js │ ├── App.scss │ ├── components │ │ ├── Header.js │ │ ├── Task.js │ │ ├── TaskAdd.js │ │ ├── TaskList.js │ │ └── ToDo.js │ └── index.js ├── yarn-error.log └── yarn.lock沢山のファイルがありますが、今回の記事で注目するのは
app/src以下のファイルのみです。フォルダ構成src ├── App.js ├── App.scss ├── components │ ├── Header.js │ ├── Task.js │ ├── TaskAdd.js │ ├── TaskList.js │ └── ToDo.js └── index.jsファイルの解説(ToDo Appのコンポーネントを除く)
components配下のファイルが先ほど確認した各コンポーネントに対応しています。
後ほど、詳しく見ていきます。Header.js
Header.jsはアプリのタイトルのToDoを表しているのみです。
公式ドキュメントで出てくるHelloWorldと同じですね。Header.jsimport React from "react"; const Header = () => { return ( <header> <h1>ToDo</h1> </header> ); }; export default Header;App.scss
App.scssはレイアウトの部分を書いてあります。
デフォルトの状態では見にくいので、見やすい様に少しレイアウトを調整しています。
今回の内容とはあまり関係無いので割愛します。index.js
index.jsはAppコンポーネントをレンダリンしています。
では、Appコンポーネントを見てみましょう。index.jsimport React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render(<App />, document.getElementById('root'));App.js
App.jsはHeaderコンポーネントとToDoコンポーネントをレンダリングしています。App.jsimport React from 'react'; import 'reset-css' import Header from './components/Header'; import ToDo from './components/ToDo' import './App.scss'; function App() { return ( <div className="App"> <Header /> <ToDo /> </div> ); } export default App;4. Reactで保持するデータについて
各コンポーネントの説明に入る前にReactで保持して、各コンポーネントにどんなデータを渡すのかを説明します。
今回のToDoアプリはタスクの作成、更新、削除ができます。
では、ToDo AddコンポーネントとTask Listコンポーネントで共通で使用したいデータは何でしょうか??
言い換えると、ToDoコンポーネントで持っておいた方が楽なデータは何でしょうか??
タスクの新規作成時には、既に同じ名前のタスクが登録されていないか確認したいのでタスクのリストはTask Listコンポーネントで保持するより
ToDoコンポーネントに持つ方が、ToDo Addコンポーネントが参照しやすく無いでしょうか??
また、今回はDBなどの保存する機能はありませんが後々のことを考慮するとなれば各タスクの識別子(id)が必要になってくると考えれます。
なので、ToDoコンポーネントにはタスクのIDを持たせる様にします。
ここまでを、再度コンポーネントのイメージと一緒に確認すると以下の様になります。本当は更新した際のステータスもToDoコンポーネントで保持するべきだと思いますが省略。
5. 各コンポーネントの解説
各コンポーネントの関係をイメージにすると以下のようになります。
一つずつ確認しながら、見てみてください。5-1.全体図
5-2. ToDo.js
5-2-1. ソース全体
ToDo.jsimport React from "react"; import TaskAdd from './TaskAdd'; import TaskList from './TaskList'; class ToDo extends React.Component { constructor(props) { super(props); this.state = { TaskList: [], TaskId: 0 }; this.deleteTask = this.deleteTask.bind(this); this.addTask = this.addTask.bind(this); } deleteTask(TaskId) { var NewTaskList = this.state.TaskList; let TaskIndex = 0; for (var i = 0; i < NewTaskList.length; i++) { if (NewTaskList[i].key.toString() === TaskId.toString()) { TaskIndex = i; } } NewTaskList.splice(TaskIndex, 1); this.setState({ TaskList: NewTaskList }); } addTask(newTask) { let TaskList = this.state.TaskList; TaskList.push(newTask); this.setState({ TaskList: TaskList }); } render() { return ( <main className='todo-component'> <TaskAdd id={this.state.TaskId} addTask={this.addTask} TaskList={this.state.TaskList} deleteTask={this.deleteTask} /> <TaskList TaskList={this.state.TaskList} /> </main> ); } } export default ToDo;5-2-2. モジュールのインポート
importimport React from "react"; import TaskAdd from './TaskAdd'; import TaskList from './TaskList';5-2-3. stateの定義と関数の登録
タスクのリストとして TaskListタスクの識別子(id)として TaskIdをstateとして定義しています。
deleteTaskはタスクの削除addTaskはタスクの登録を示しています。
ToDoコンポーネントのconstructorconstructor(props) { super(props); this.state = { TaskList: [], TaskId: 0 }; this.deleteTask = this.deleteTask.bind(this); this.addTask = this.addTask.bind(this); }5-2-4. deleteTask
タスクの削除はタスクIDを元にタスクリストから削除対象のリストのインデックスを探します。
そして、インデックスが見つかればタスクリストに対してspliceで対象のタスクの削除を実行します。
削除が完了したら、this.setStateでタスクリストを更新します。ToDoコンポーネントのdeleteTaskdeleteTask(TaskId) { var NewTaskList = this.state.TaskList; let TaskIndex = 0; for (var i = 0; i < NewTaskList.length; i++) { if (NewTaskList[i].key.toString() === TaskId.toString()) { TaskIndex = i; } } NewTaskList.splice(TaskIndex, 1); this.setState({ TaskList: NewTaskList }); }5-2-5. addTask
新しいタスクの情報をタスクリストに
pushして更新しています。
後ほど、説明しますがnewTaskはTaskコンポーネントになっています。ToDoコンポーネントのaddTaskaddTask(newTask) { let TaskList = this.state.TaskList; TaskList.push(newTask); this.setState({ TaskList: TaskList }); }5-2-6. render
TaskAddには、以下のpropが送られています。
- TaskId
- TaskList
addTask関数deleteTask関数
TaskListにはタスクリストのみがpropとして送られています。なぜ
TaskAddの方に削除する関数を持たせているのか疑問に思う方も居ると思いますが
後に解決すると思うので、ここでは送っているということだけ覚えておいてください。ToDoコンポーネントのrenderrender() { return ( <main className='todo-component'> <TaskAdd id={this.state.TaskId} addTask={this.addTask} TaskList={this.state.TaskList} deleteTask={this.deleteTask} /> <TaskList TaskList={this.state.TaskList} /> </main> ); }5-3. TaskAdd.js
5-3-1. ソース全体
TaskAddimport React from "react"; import Task from './Task' class TaskAdd extends React.Component { constructor(props) { super(props); this.state = { NewTask: '', TaskId: this.props.id, ErrorMessage: '', }; this.handleClick = this.handleClick.bind(this); this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({ NewTask: event.target.value }); } handleClick() { // 空白チェック if (this.state.NewTask === '') { this.setState({ ErrorMessage: '入力が空です。' }) return 0 } // 重複チェック for (var i = 0; i < this.props.TaskList.length; i++) { if (this.props.TaskList[i].props.name === this.state.NewTask) { this.setState({ ErrorMessage: 'タスク名が重複しています。' }) return 0 } } let TaskId = this.state.TaskId; this.props.addTask(<Task key={TaskId} id={TaskId} name={this.state.NewTask} deleteTask={this.props.deleteTask} />); this.setState({ TaskId: TaskId + 1 }) this.setState({ NewTask: '' }) this.setState({ ErrorMessage: '' }) } render() { return ( <section className='task-creator'> <h2>Task Add</h2> <input className='task-item-text' type="text" placeholder="Task" value={this.state.NewTask} onChange={this.handleChange} /> <button className='task-add-btn' type="button" onClick={this.handleClick}>Add</button> <p className='error-msg'>{this.state.ErrorMessage}</p> </section> ); } } export default TaskAdd;5-3-2. モジュールのインポート
タスクを新規に作成するので
Taskコンポーネントをインポートしています。importimport React from "react"; import Task from './Task'5-3-3. stateの定義と関数の登録
- 新規タスク名
- タスクID(ToDoコンポーネントから受け取ったもの)
エラーメッセージ
handleClickはAddボタン押下時の関数
handleChangeはテキストボックスの変更を検知してstateの新規タスク名を書き換えていますTaskAddコンポーネントのconstructorconstructor(props) { super(props); this.state = { NewTask: '', TaskId: this.props.id, ErrorMessage: '', }; this.handleClick = this.handleClick.bind(this); this.handleChange = this.handleChange.bind(this);5-3-4. handleChange
シンプルにsetStateで値を書き換えています。
renderの箇所でonChangeで指定するとできます。
JavaScriptを書いてた人なら、平常運転的な感じですかね?TaskAddコンポーネントのhandleChangehandleChange(event) { this.setState({ NewTask: event.target.value }); }5-3-5. handleClick
Addボタン押下時の関数です。
空白チェックや重複チェックは特に言うことは無いと思います。
propsで受け取ったTaskListをここで使用して、重複の確認をしています。
処理の途中で抜けるのにreturn 0にしてるけど、あまりよろしく無いかも。。。。諸々のチェックが完了すると、
ToDoコンポーネントからpropsとして受け取ったaddTask関数を使用してリストに新しいタスクを登録しています。
タスク自体はTaskとしてコンポーネント化しているので、addTaskの引数はTaskになります。deleteTaskをTaskAddコンポーネントに持たせている理由ですが、タスクIDと削除機能がセットである方が削除処理が書きやすいからです。
そして、削除処理を持たせることができるタイミングがタスクの新規作成時だからです。
何か別の方法も考えられそうですが。。。(状態管理のフレームワークを使わない方向で。。)最後のsetStateは新しいタスクIDを振ったり、タスクのテキストボックスやエラーメッセージを空白にしているのみです。
TaskAddコンポーネントのhandleClickhandleClick() { // 空白チェック if (this.state.NewTask === '') { this.setState({ ErrorMessage: '入力が空です。' }) return 0 } // 重複チェック for (var i = 0; i < this.props.TaskList.length; i++) { if (this.props.TaskList[i].props.name === this.state.NewTask) { this.setState({ ErrorMessage: 'タスク名が重複しています。' }) return 0 } } let TaskId = this.state.TaskId; this.props.addTask(<Task key={TaskId} id={TaskId} name={this.state.NewTask} deleteTask={this.props.deleteTask} />); this.setState({ TaskId: TaskId + 1 }) this.setState({ NewTask: '' }) this.setState({ ErrorMessage: '' }) }5-3-6. render
特に説明はいらないと思います。普通のhtmlタグを並べているだけです。
TaskAddコンポーネントのrenderrender() { return ( <section className='task-creator'> <h2>Task Add</h2> <input className='task-item-text' type="text" placeholder="Task" value={this.state.NewTask} onChange={this.handleChange} /> <button className='task-add-btn' type="button" onClick={this.handleClick}>Add</button> <p className='error-msg'>{this.state.ErrorMessage}</p> </section> );5-4. Task.js
5-4-1. ソース全体
Task.jsimport React from "react"; class Task extends React.Component { constructor(props) { super(props); this.state = { isDone: this.props.isDone, } this.handleChange = this.handleChange.bind(this); } checkTaskStatus(isDone) { if (isDone) { return 'isDone task-item-label' } else { return 'WorkInProgress task-item-label' } } handleChange() { if (this.state.isDone) { this.setState({ isDone: false }) } else { this.setState({ isDone: true }) } } render() { return ( <li className='task-item-row'> <input id={'task-id-' + this.props.id.toString()} className='task-item-checkbox' type='checkbox' onChange={this.handleChange}></input> <label htmlFor={'task-id-' + this.props.id.toString()} className={this.checkTaskStatus(this.state.isDone)}>{this.props.name}</label> <i className="material-icons icon" onClick={() => this.props.deleteTask(this.props.id)}>delete</i> </li> ); } } export default Task;5-4-2. stateの定義と関数の登録
stateにはタスクが完了したかどうかを判定するis_Doneフラグ
handleChangeはタスクのチェックボックスのイベント処理に使用しています。Taskコンポーネントのconstructorconstructor(props) { super(props); this.state = { isDone: this.props.isDone, } this.handleChange = this.handleChange.bind(this); }5-4-3. checkTaskStatus
タスクのラベルにcssのクラスを適応させています。
ちょっと不格好。。TaskコンポーネントのcheckTaskStatuscheckTaskStatus(isDone) { if (isDone) { return 'isDone task-item-label' } else { return 'WorkInProgress task-item-label' }5-4-4. handleChange
stateのis_Doneを見て判定しているだけです。
TaskコンポーネントのhandleChangehandleChange() { if (this.state.isDone) { this.setState({ isDone: false }) } else { this.setState({ isDone: true }) } }5-4-5. render
普通のhtmlタグにOnChangeやOnClickのイベント処理を追加しているだけです。
onClick={() => this.props.deleteTask(this.props.id)}
こう書けば、handleChangeみたに定義して書かなくていいから楽ですよね。Taskコンポーネントのrenderrender() { return ( <li className='task-item-row'> <input id={'task-id-' + this.props.id.toString()} className='task-item-checkbox' type='checkbox' onChange={this.handleChange}></input> <label htmlFor={'task-id-' + this.props.id.toString()} className={this.checkTaskStatus(this.state.isDone)}>{this.props.name}</label> <i className="material-icons icon" onClick={() => this.props.deleteTask(this.props.id)}>delete</i> </li> ); }5-5. TaskList.js
5-5-1. ソース全体
renderでToDoコンポーネントから受け取ったTaskListを表示しているだけです。
TaskListimport React from "react"; class TaskList extends React.Component { render() { return ( <section className='task-list'> <h2>Task List</h2> <ul> {this.props.TaskList} </ul> </section> ); } } export default TaskList;6. まとめ
今回は結構なボリュームになってしまいましたが、うまく説明できたでしょうか?(ちょっと心配・・・)
ほんの数日前にReactを改めて勉強しなおして、それっぽいものは作れたかなと思っていたりします。
私は公式のドキュメントやチュートリアルだけでは、なかなか手が進まなくて四苦八苦したので
今回の記事作成の過程でReactと少しは仲良くなれた気がします。
まだまだ、HookやReduxなど関門が立ちはだかっているのが見えますが、地道に取り組んで行きたいと思っています。
また、最後までお読みくださりありがとうございます。
もしかしたら、有識者の方から見たらデタラメな書き方をしているかもしれませんがご容赦ください。
質問、指摘、コメントは大歓迎ですので、よろしくお願いします。
- 投稿日:2020-01-07T00:15:11+09:00
ReactでToDoアプリを作成してみました
はじめに
この記事ではJavaScriptのライブラリであるReactを使用して簡単なToDoアプリの実装を行います。
クライアント側のみの実装になります。
Reactのドキュメントやチュートリアル(三目並べ)を一通り行った後の練習になるように書きたいと思います。
環境構築に関しては、create-react-appを使用して作成しています。環境構築に関しては以前書いた記事があります。
もちろん、オレオレな環境でもokです。
Reactについては初心者なので認識の齟齬や到らない点も多々あると思いますが、よろしくお願いします。目次
- 環境準備
- コンポーネントの確認
- ファイル構成
- Reactで保持するデータについて
- 各コンポーネントの解説
- まとめ
1. 環境準備
以下からソースコードを引っ張ってきます。
ソースコード
gitでクローンした場合は、ブランチはtodo-app-pure-cssです。(何かダサい名前なのは目を瞑っておいてください。。。)
動作を確認するために、ブラウザ上で確認できる環境も用意しました。1-1. DockerImageのビルド
docker build --rm -f "react-tutorial/Dockerfile" -t react-tutorial:latest "react-tutorial"1-2. DockerContainerの起動
$ docker run --rm -it -v ${PWD}/app:/home/react-tutorial -p 3000:3000/tcp react-tutorial:latest /bin/bash root@03887209ce2d:/home#1-3. 追加のパッケージをインストール(コンテナの内部で操作してます)
root@03887209ce2d:/home# cd react-tutorial root@03887209ce2d:/home/react-tutorial# yarn install1-4. Reactアプリケーションの起動
root@03887209ce2d:/home/react-tutorial# yarn start1-5. ブラウザで確認
Reactアプリケーションの起動に成功すると、以下のような表示がされます。
Compiled successfully! You can now view react-tutorial in the browser. Local: http://localhost:3000/ On Your Network: http://172.17.0.3:3000/ Note that the development build is not optimized. To create a production build, use yarn build.ブラウザで
http://localhost:3000/を入力して開いてみましょう。
そうすると、下記の様な画面が表示されるはずです。
今回は、この画面をReactで作成していきたいと思います。2. コンポーネントの確認
ReactはUIのパーツをコンポーネントという独立した一つの部品とみなして構成していきます。
今回の例では下記の様に分割しました。ToDoアプリケーションを構成するコンポーネントは全部で4つあります。
ToDo
ToDoアプリケーションの全体を表しますTaskAdd
新しいタスクの追加を行いますTaskList
追加されたタスクをリストにして表示しますTaskItem
一つのタスクを表します3. ファイル構成
ファイル構成を確認しましょう。
フォルダ構成. ├── Dockerfile ├── README.md └── app ├── README.md ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.js │ ├── App.scss │ ├── components │ │ ├── Header.js │ │ ├── Task.js │ │ ├── TaskAdd.js │ │ ├── TaskList.js │ │ └── ToDo.js │ └── index.js ├── yarn-error.log └── yarn.lock沢山のファイルがありますが、今回の記事で注目するのは
app/src以下のファイルのみです。フォルダ構成src ├── App.js ├── App.scss ├── components │ ├── Header.js │ ├── Task.js │ ├── TaskAdd.js │ ├── TaskList.js │ └── ToDo.js └── index.jsファイルの解説(ToDo Appのコンポーネントを除く)
components配下のファイルが先ほど確認した各コンポーネントに対応しています。
後ほど、詳しく見ていきます。Header.js
Header.jsはアプリのタイトルのToDoを表しているのみです。
公式ドキュメントで出てくるHelloWorldと同じですね。Header.jsimport React from "react"; const Header = () => { return ( <header> <h1>ToDo</h1> </header> ); }; export default Header;App.scss
App.scssはレイアウトの部分を書いてあります。
デフォルトの状態では見にくいので、見やすい様に少しレイアウトを調整しています。
今回の内容とはあまり関係無いので割愛します。index.js
index.jsはAppコンポーネントをレンダリンしています。
では、Appコンポーネントを見てみましょう。index.jsimport React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render(<App />, document.getElementById('root'));App.js
App.jsはHeaderコンポーネントとToDoコンポーネントをレンダリングしています。App.jsimport React from 'react'; import 'reset-css' import Header from './components/Header'; import ToDo from './components/ToDo' import './App.scss'; function App() { return ( <div className="App"> <Header /> <ToDo /> </div> ); } export default App;4. Reactで保持するデータについて
各コンポーネントの説明に入る前にReactで保持して、各コンポーネントにどんなデータを渡すのかを説明します。
今回のToDoアプリはタスクの作成、更新、削除ができます。
では、ToDo AddコンポーネントとTask Listコンポーネントで共通で使用したいデータは何でしょうか??
言い換えると、ToDoコンポーネントで持っておいた方が楽なデータは何でしょうか??
タスクの新規作成時には、既に同じ名前のタスクが登録されていないか確認したいのでタスクのリストはTask Listコンポーネントで保持するより
ToDoコンポーネントに持つ方が、ToDo Addコンポーネントが参照しやすく無いでしょうか??
また、今回はDBなどの保存する機能はありませんが後々のことを考慮するとなれば各タスクの識別子(id)が必要になってくると考えれます。
なので、ToDoコンポーネントにはタスクのIDを持たせる様にします。
ここまでを、再度コンポーネントのイメージと一緒に確認すると以下の様になります。本当は更新した際のステータスもToDoコンポーネントで保持するべきだと思いますが省略。
5. 各コンポーネントの解説
各コンポーネントの関係をイメージにすると以下のようになります。
一つずつ確認しながら、見てみてください。5-1.全体図
5-2. ToDo.js
5-2-1. ソース全体
ToDo.jsimport React from "react"; import TaskAdd from './TaskAdd'; import TaskList from './TaskList'; class ToDo extends React.Component { constructor(props) { super(props); this.state = { TaskList: [], TaskId: 0 }; this.deleteTask = this.deleteTask.bind(this); this.addTask = this.addTask.bind(this); } deleteTask(TaskId) { var NewTaskList = this.state.TaskList; let TaskIndex = 0; for (var i = 0; i < NewTaskList.length; i++) { if (NewTaskList[i].key.toString() === TaskId.toString()) { TaskIndex = i; } } NewTaskList.splice(TaskIndex, 1); this.setState({ TaskList: NewTaskList }); } addTask(newTask) { let TaskList = this.state.TaskList; TaskList.push(newTask); this.setState({ TaskList: TaskList }); } render() { return ( <main className='todo-component'> <TaskAdd id={this.state.TaskId} addTask={this.addTask} TaskList={this.state.TaskList} deleteTask={this.deleteTask} /> <TaskList TaskList={this.state.TaskList} /> </main> ); } } export default ToDo;5-2-2. モジュールのインポート
importimport React from "react"; import TaskAdd from './TaskAdd'; import TaskList from './TaskList';5-2-3. stateの定義と関数の登録
タスクのリストとして TaskListタスクの識別子(id)として TaskIdをstateとして定義しています。
deleteTaskはタスクの削除addTaskはタスクの登録を示しています。
ToDoコンポーネントのconstructorconstructor(props) { super(props); this.state = { TaskList: [], TaskId: 0 }; this.deleteTask = this.deleteTask.bind(this); this.addTask = this.addTask.bind(this); }5-2-4. deleteTask
タスクの削除はタスクIDを元にタスクリストから削除対象のリストのインデックスを探します。
そして、インデックスが見つかればタスクリストに対してspliceで対象のタスクの削除を実行します。
削除が完了したら、this.setStateでタスクリストを更新します。ToDoコンポーネントのdeleteTaskdeleteTask(TaskId) { var NewTaskList = this.state.TaskList; let TaskIndex = 0; for (var i = 0; i < NewTaskList.length; i++) { if (NewTaskList[i].key.toString() === TaskId.toString()) { TaskIndex = i; } } NewTaskList.splice(TaskIndex, 1); this.setState({ TaskList: NewTaskList }); }5-2-5. addTask
新しいタスクの情報をタスクリストに
pushして更新しています。
後ほど、説明しますがnewTaskはTaskコンポーネントになっています。ToDoコンポーネントのaddTaskaddTask(newTask) { let TaskList = this.state.TaskList; TaskList.push(newTask); this.setState({ TaskList: TaskList }); }5-2-6. render
TaskAddには、以下のpropが送られています。
- TaskId
- TaskList
addTask関数deleteTask関数
TaskListにはタスクリストのみがpropとして送られています。なぜ
TaskAddの方に削除する関数を持たせているのか疑問に思う方も居ると思いますが
後に解決すると思うので、ここでは送っているということだけ覚えておいてください。ToDoコンポーネントのrenderrender() { return ( <main className='todo-component'> <TaskAdd id={this.state.TaskId} addTask={this.addTask} TaskList={this.state.TaskList} deleteTask={this.deleteTask} /> <TaskList TaskList={this.state.TaskList} /> </main> ); }5-3. TaskAdd.js
5-3-1. ソース全体
TaskAddimport React from "react"; import Task from './Task' class TaskAdd extends React.Component { constructor(props) { super(props); this.state = { NewTask: '', TaskId: this.props.id, ErrorMessage: '', }; this.handleClick = this.handleClick.bind(this); this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({ NewTask: event.target.value }); } handleClick() { // 空白チェック if (this.state.NewTask === '') { this.setState({ ErrorMessage: '入力が空です。' }) return 0 } // 重複チェック for (var i = 0; i < this.props.TaskList.length; i++) { if (this.props.TaskList[i].props.name === this.state.NewTask) { this.setState({ ErrorMessage: 'タスク名が重複しています。' }) return 0 } } let TaskId = this.state.TaskId; this.props.addTask(<Task key={TaskId} id={TaskId} name={this.state.NewTask} deleteTask={this.props.deleteTask} />); this.setState({ TaskId: TaskId + 1 }) this.setState({ NewTask: '' }) this.setState({ ErrorMessage: '' }) } render() { return ( <section className='task-creator'> <h2>Task Add</h2> <input className='task-item-text' type="text" placeholder="Task" value={this.state.NewTask} onChange={this.handleChange} /> <button className='task-add-btn' type="button" onClick={this.handleClick}>Add</button> <p className='error-msg'>{this.state.ErrorMessage}</p> </section> ); } } export default TaskAdd;5-3-2. モジュールのインポート
タスクを新規に作成するので
Taskコンポーネントをインポートしています。importimport React from "react"; import Task from './Task'5-3-3. stateの定義と関数の登録
- 新規タスク名
- タスクID(ToDoコンポーネントから受け取ったもの)
エラーメッセージ
handleClickはAddボタン押下時の関数
handleChangeはテキストボックスの変更を検知してstateの新規タスク名を書き換えていますTaskAddコンポーネントのconstructorconstructor(props) { super(props); this.state = { NewTask: '', TaskId: this.props.id, ErrorMessage: '', }; this.handleClick = this.handleClick.bind(this); this.handleChange = this.handleChange.bind(this);5-3-4. handleChange
シンプルにsetStateで値を書き換えています。
renderの箇所でonChangeで指定するとできます。
JavaScriptを書いてた人なら、平常運転的な感じですかね?TaskAddコンポーネントのhandleChangehandleChange(event) { this.setState({ NewTask: event.target.value }); }5-3-5. handleClick
Addボタン押下時の関数です。
空白チェックや重複チェックは特に言うことは無いと思います。
propsで受け取ったTaskListをここで使用して、重複の確認をしています。
処理の途中で抜けるのにreturn 0にしてるけど、あまりよろしく無いかも。。。。諸々のチェックが完了すると、
ToDoコンポーネントからpropsとして受け取ったaddTask関数を使用してリストに新しいタスクを登録しています。
タスク自体はTaskとしてコンポーネント化しているので、addTaskの引数はTaskになります。deleteTaskをTaskAddコンポーネントに持たせている理由ですが、タスクIDと削除機能がセットである方が削除処理が書きやすいからです。
そして、削除処理を持たせることができるタイミングがタスクの新規作成時だからです。
何か別の方法も考えられそうですが。。。(状態管理のフレームワークを使わない方向で。。)最後のsetStateは新しいタスクIDを振ったり、タスクのテキストボックスやエラーメッセージを空白にしているのみです。
TaskAddコンポーネントのhandleClickhandleClick() { // 空白チェック if (this.state.NewTask === '') { this.setState({ ErrorMessage: '入力が空です。' }) return 0 } // 重複チェック for (var i = 0; i < this.props.TaskList.length; i++) { if (this.props.TaskList[i].props.name === this.state.NewTask) { this.setState({ ErrorMessage: 'タスク名が重複しています。' }) return 0 } } let TaskId = this.state.TaskId; this.props.addTask(<Task key={TaskId} id={TaskId} name={this.state.NewTask} deleteTask={this.props.deleteTask} />); this.setState({ TaskId: TaskId + 1 }) this.setState({ NewTask: '' }) this.setState({ ErrorMessage: '' }) }5-3-6. render
特に説明はいらないと思います。普通のhtmlタグを並べているだけです。
TaskAddコンポーネントのrenderrender() { return ( <section className='task-creator'> <h2>Task Add</h2> <input className='task-item-text' type="text" placeholder="Task" value={this.state.NewTask} onChange={this.handleChange} /> <button className='task-add-btn' type="button" onClick={this.handleClick}>Add</button> <p className='error-msg'>{this.state.ErrorMessage}</p> </section> );5-4. Task.js
5-4-1. ソース全体
Task.jsimport React from "react"; class Task extends React.Component { constructor(props) { super(props); this.state = { isDone: this.props.isDone, } this.handleChange = this.handleChange.bind(this); } checkTaskStatus(isDone) { if (isDone) { return 'isDone task-item-label' } else { return 'WorkInProgress task-item-label' } } handleChange() { if (this.state.isDone) { this.setState({ isDone: false }) } else { this.setState({ isDone: true }) } } render() { return ( <li className='task-item-row'> <input id={'task-id-' + this.props.id.toString()} className='task-item-checkbox' type='checkbox' onChange={this.handleChange}></input> <label htmlFor={'task-id-' + this.props.id.toString()} className={this.checkTaskStatus(this.state.isDone)}>{this.props.name}</label> <i className="material-icons icon" onClick={() => this.props.deleteTask(this.props.id)}>delete</i> </li> ); } } export default Task;5-4-2. stateの定義と関数の登録
stateにはタスクが完了したかどうかを判定するis_Doneフラグ
handleChangeはタスクのチェックボックスのイベント処理に使用しています。Taskコンポーネントのconstructorconstructor(props) { super(props); this.state = { isDone: this.props.isDone, } this.handleChange = this.handleChange.bind(this); }5-4-3. checkTaskStatus
タスクのラベルにcssのクラスを適応させています。
ちょっと不格好。。TaskコンポーネントのcheckTaskStatuscheckTaskStatus(isDone) { if (isDone) { return 'isDone task-item-label' } else { return 'WorkInProgress task-item-label' }5-4-4. handleChange
stateのis_Doneを見て判定しているだけです。
TaskコンポーネントのhandleChangehandleChange() { if (this.state.isDone) { this.setState({ isDone: false }) } else { this.setState({ isDone: true }) } }5-4-5. render
普通のhtmlタグにOnChangeやOnClickのイベント処理を追加しているだけです。
onClick={() => this.props.deleteTask(this.props.id)}
こう書けば、handleChangeみたに定義して書かなくていいから楽ですよね。Taskコンポーネントのrenderrender() { return ( <li className='task-item-row'> <input id={'task-id-' + this.props.id.toString()} className='task-item-checkbox' type='checkbox' onChange={this.handleChange}></input> <label htmlFor={'task-id-' + this.props.id.toString()} className={this.checkTaskStatus(this.state.isDone)}>{this.props.name}</label> <i className="material-icons icon" onClick={() => this.props.deleteTask(this.props.id)}>delete</i> </li> ); }5-5. TaskList.js
5-5-1. ソース全体
renderでToDoコンポーネントから受け取ったTaskListを表示しているだけです。
TaskListimport React from "react"; class TaskList extends React.Component { render() { return ( <section className='task-list'> <h2>Task List</h2> <ul> {this.props.TaskList} </ul> </section> ); } } export default TaskList;6. まとめ
今回は結構なボリュームになってしまいましたが、うまく説明できたでしょうか?(ちょっと心配・・・)
ほんの数日前にReactを改めて勉強しなおして、それっぽいものは作れたかなと思っていたりします。
私は公式のドキュメントやチュートリアルだけでは、なかなか手が進まなくて四苦八苦したので
今回の記事作成の過程でReactと少しは仲良くなれた気がします。
まだまだ、HookやReduxなど関門が立ちはだかっているのが見えますが、地道に取り組んで行きたいと思っています。
また、最後までお読みくださりありがとうございます。
もしかしたら、有識者の方から見たらデタラメな書き方をしているかもしれませんがご容赦ください。
質問、指摘、コメントは大歓迎ですので、よろしくお願いします。








