【React】コンポーネントの出しわけ
あるプロジェクトのコードを読んでいて、「JSXでのコンポーネントの出しわけがスマートじゃない!」
と思ったので、良い例と悪い例を紹介します。
条件に合致する場合のみコンポーネントをレンダリングしたい
例として、
サイト全体で使う Header コンポーネントがあり、
サイトトップページ以外では、ホームに戻すリンクを設置したい場合を想定。
悪い例
{!props.home ? ( <Link href="/"> <a>Back to home</a> </Link> ) : null}
三項演算子を使って、条件を満たさないときはnullを返却している。
nullを返却しているのが冗長だと感じます。
コンポーネントをだし分ける条件が3つ以上ある場合
出しわけが3つ以上ある場合を実装している箇所でこんなコードを見ました。
例がすぐに思いつかず、シンプルなコンポーネントになってしまっていますが、本当はもっと複雑なものだと思ってください…
悪い例
{() => { switch (place) { case 'home': return <div>home</div>; case 'about': return <div>about</div>; case 'mail': return <div>mail</div>; } }}
JSX内にswitch文を書いています。
JSXではあまりロジックは持ち込まず、できるだけ表示に関することに専念させたいです。
良い例
... // ↓JS const func = place => { switch (place) { case 'home': return <div>home</div>; case 'about': return <div>about</div>; case 'mail': return <div>mail</div>; } }; ... // ↓JSX ... {func(place)} ...
条件分岐部分はJSXの外に切り出した方が、ロジックを持ち込まずスッキリします。
この書き方がベストかどうかは置いといて、先述のコードよりかはマシかと思います。。
終わり
こういう話を持ち出すと好き嫌いが分かれるので、
今回のも、私の好みの書き方として捉えていただけると幸いです。
phpの分割代入について書き留めておく
phpの分割代入で、
使えそうだなーって思ったのを自分用に書き留めておく。
配列の中身を一つずつ変数に詰め直す作業。
分割代入を使わないとこんな感じでめんどくさい。
$fruits = ['apple', 'orange', 'banana']; $apple = $fruits[0]; $orange = $fruits[1]; $banana = $fruits[2];
分割代入を使うと
こんな感じ
$fruits = ['apple', 'orange', 'banana']; [$apple, $orange, $banana] = $fruits; var_dump($orange); //orange
$fruits配列の左から順に代入していってくれる。
お次は連想配列のパターン
分割代入を使わないで変数に詰め込み直す作業をすると↓
$fruits = ['apple' => 'りんご', 'orange' => 'オレンジ', 'banana' => 'バナナ']; $apple = $fruits['apple']; $orange = $fruits['orange']; $banana = $fruits['banana'];
分割代入を使うと
$fruits = ['apple' => 'りんご', 'orange' => 'オレンジ', 'banana' => 'バナナ']; ['apple' => $apple, 'orange' => $orange, 'banana' => $banana] = $fruits; var_dump($banana); //バナナ
スッキリかける。横に長くなってしまうけれども。
実際に使えそうだと思ったケース。
各チームのポイントとランクだけ取り出したい。って場合↓
$teams = array
(
'Liverpool' => array
(
'name' => 'Liverpool',
'points' => 52,
'rank' => 1
),
'Everton' => array
(
'name' => 'Liverpool',
'points' => 25,
'rank' => 10
)
);
foreach ($teams as $team) {
['points' => $points, 'rank' => $rank] = $team;
var_dump($points);
}
javascript(ES6) アロー関数
アロー関数メモ
アロー関数を使わない場合
const numbers = [1, 24, 3, 45, 23]; const doubleNumbers = numbers.map(function(number){ return number * 2; }); //配列の数字を2倍にする関数
アロー関数を使う場合、functionを省くことができます。その代わり矢印 => を引数の後ろに加えます。
const numbers = [1, 24, 3, 45, 23]; const doubleNumbers = numbers.map((number) => { return number * 2; });
もっと省略することもできます。
・受け取る引数が一つだけの場合、引数の()を省くことができる
・関数内の文が1文で終わる場合{}とreturn を省くことができる
const numbers = [1, 24, 3, 45, 23]; const doubleNumbers = numbers.map(number => number * 2);
引数の数が0とか2とかの場合は()を省けないです。
varとconstとlet
javascriptにおいて
varとconstとletの違いはなんなのか。
constとletが新しくて、varはもう使わない。
constは定数。
とか、そんな感じでしか知らなかったので、少し調べてみました。
var,const,letの違いは、スコープと巻き上げ。らしい...
この違いを説明するのに、一旦はconstを置いといて、
varとletでの違いを書いていく。
1.スコープ
一言で違いをいうと、varは関数スコープでletはブロックスコープである。
varの場合
function callName(){ var name = 'Taro'; console.log(name); //Taro if (true) { var name = 'Jiro'; console.log(name); //Jiro } console.log(name); //Jiro }
これはvarを使った場合の例。
varは関数スコープなので、ifやforの中で変数を定義しても、スコープ範囲は関数内になるので、if文の外側にも反映されるようになっている。
if文の中であろうが外であろうが、関係なし。区別をつけない。
var name = 'Jiro'; をif文の中で定義しているが、if文の外で変数nameを出力してもそれが反映されていることがわかる。
一方のletは、、、
function callName(){ let name = 'Taro'; console.log(name); //Taro if (true) { let name = 'Jiro'; console.log(name); //Jiro } console.log(name); //Taro }
letはブロックスコープなので、ifやforの中で変数を定義すると、スコープ範囲はブロック内になるので、if文の中だけで反映されるようになっている。
if文の中と外で区別される。
let name = 'Jiro'; をif文の中で定義しているが、if文の外で変数nameを出力してもそれが反映されていないことがわかる。
以上が、varとletのスコープの違いでした。
個人的にはletの方が自然な感じがあります。(他の言語は知りませんがjavaはそうだったので)
2.変数の巻き上げ
変数の巻き上げとは、スコープ内で宣言した変数は、どこに書いてあろうと、スコープ内の一番はじめに定義されること。を意味する。
変数の巻き上げ自体はvarでもletでも起こるのだが、挙動が違うらしい。
varの場合
var name = 'Jiro'; function callName(){ console.log(name); //undefind var name = 'Taro'; console.log(name); //Taro }
変数nameを関数callName()内の2行目で定義しているが、変数の巻き上げにより、スコープ内の先頭で定義されたことになる。
よって、グローバル変数のname='Jiro'は使われずに、スコープ内で定義された方を参照する動きになる。
つまりは、こう書いてるのと一緒ということ↓
var name = 'Jiro'; function callName(){ var name; //スコープ内の先頭で定義されたことになっている。 console.log(name); //undefind var name = 'Taro'; console.log(name); //Taro }
変数が初期化されていなかったら、出力結果はundefindになる。
これがvarの巻き上げの挙動。
一方のletは
let name = 'Jiro'; function callName(){ console.log(name); //Uncaught ReferenceError: Cannot access 'name' before initialization let name = 'Taro'; console.log(name); }
ちなみに、巻き上げが起こるのでこれと同じことになる↓
let name = 'Jiro'; function callName(){ let name; //スコープ内の先頭で定義されたことになる。 console.log(name); //Uncaught ReferenceError: Cannot access 'name' before initialization let name = 'Taro'; console.log(name); }
letの場合はundefindではなく、エラーになってしまう。
letの場合、変数の巻き上げは起こっているのだが、変数が初期化されていないとエラーになってしまう。
これがletの巻き上げの挙動
以上がvarとletの大きな違いである。
個人的にはletの方が慣れた挙動をしていると感じた。
最後に、
letとconstの違い
簡単に言えば、letは再代入可。constは再代入不可。
constはconstantの略で、定数っていう意味。
ただ、constは要素の再代入は不可であるが、オブジェクト内の要素は変えることができる。
const name = 'Taro'; let age = 20; const fruits = [ {name: 'apple', price: 100}, {name: 'orange', price: 80}, ]; name = 'Jiro'; //エラーが起きる age = 21; //可能 fruits[0].price = 90; //オブジェクト内の要素の変更は可能
まとめ
以上が、var,let,constの違いでした。
できるだけ、letとconstを使っていきたいですが、varを使ってるコードもまだまだ存在するので、そこのコードの改修となると、
見極めていい感じに使い分ける必要がありそう。。。
テンプレートリテラル
javascriptのテンプレートリテラルを学んだので、アウトプット。
Template literal は組み込み式を扱うことができる文字列リテラルです。複数行文字列や文字列内挿機能を使用できます。ES2015 / ES6 仕様の以前のエディションでは、"template strings" と呼ばれていました。
`${~}`を使うと、+ を使わずに文字結合をすることができる。
バッククォートで文字列を囲み、変数を使いたい時は${~}で囲む。
実例
`${~}`を使わない場合↓
const name = 'Taro'; const age = 20; console.log('私の名前は、' + name + 'です。' + age + '歳です。');
変数を繋げるたびに、+ を使わなければならないし、
文字列に関しては、シングルクォーテーションでいちいち囲わないといけない。
面倒だし見辛い。
`${~}`を使った場合↓
const name = 'Taro'; const age = 20; console.log(`私の名前は、${name}です。${age}歳です。`);
「+」を使う必要がなく、文字列もいちいちシングルクォーテーションで囲む必要がない。
使わない場合と比較して綺麗に見える。
${}のなかでは、関数を使うこともできる。
const func = num => num * 2; console.log('3の2倍の値は' + func(3) + 'です。'); console.log(`3の2倍の値は${func(3)}です。`);
計算だってできちゃう。
console.log('3の2倍の値は' + 3 * 2 + 'です。'); console.log(`3の2倍の値は${3 * 2}です。`);
注意点
`${~}`
これ↑
最初にも書いたが、シングルクォーテーションではなく、バッククォートで囲む必要があるのをお忘れなく。
ちなみに、キーボードでバッククォートのある場所は@があるとこ
ES6の便利メソッド(forEach, map, filter, find, some, every, reduce)
配列の便利メソッド
forEach
map
filter
find
some
every
reduce
配列をいじる時に、for文で書いた場合と便利メソッドで書いた場合で、上記のメソッド達がどれだけ便利で、綺麗になるのか。
実際にコードにしてみる。
forEach
use case →配列の中身の合計を求めたい時
for文を使った場合
const numbers = [1, 24, 3, 45, 23]; let sum = 0; for (let i = 0; i < numbers.length; i++) { sum += numbers[i]; }
forEachを使った場合
const numbers = [1, 24, 3, 45, 23]; let sum = 0; numbers.forEach(function(number){ sum += number; });
map
use case → 別の配列を生成したいとき
例→fruitsという配列から名前だけを取り出した配列を生成する。
for文を使った場合
const fruits = [ {name: 'apple', price: 100}, {name: 'banana', price: 200} ]; const names = []; for (let i = 0; i < fruits.length; i++) { names.push(fruits[i].name); }
mapを使った場合
const fruits = [ {name: 'apple', price: 100}, {name: 'banana', price: 200} ]; const names = fruits.map(function(fruit){ return fruit.name; });
filter
use case → 配列から特定のものだけ取り出して新たに配列を生成したいとき。
例→fruitsという配列からpriceが100以下のものだけを取り出す。
for文を使った場合
const fruits = [ {name: 'apple', price: 100}, {name: 'banana', price: 200}, {name: 'orange', price: 99}, {name: 'cherry', price: 120} ]; const cheapFruits = []; for (let i = 0; i < fruits.length; i++) { if (fruits[i].price <= 100) {cheapFruits.push(fruits[i]);} }
filterを使った場合
const fruits = [ {name: 'apple', price: 100}, {name: 'banana', price: 200}, {name: 'orange', price: 99}, {name: 'cherry', price: 120} ]; const cheapFruits = fruits.filter(function(fruit){ return fruit.price <= 100; });
find
use case → 配列から特定の値を見つけたい時。
例→fruitsという配列からnameがorangeかつpriceが100以下の値を取り出したい。
for文を使った場合
const fruits = [ {name: 'orange', price: 130}, {name: 'banana', price: 80}, {name: 'orange', price: 99}, {name: 'cherry', price: 120} ]; let target; for (let i = 0; i < fruits.length; i++) { if (fruits[i].name === 'orange' && fruits[i].price <= 100) { target = fruits[i]; break; } }
findを使った場合
const fruits = [ {name: 'orange', price: 130}, {name: 'banana', price: 80}, {name: 'orange', price: 99}, {name: 'cherry', price: 120} ]; let target = fruits.find(function(fruit){ return fruit.name === 'orange' && fruit.price <= 100; });
some
use case → 条件を一つ一つ検証していき、一つでも当てはまるかどうか知りたい時。(論理和)
例→一つでも30点以下の教科があるかどうかを知りたい。
for文を使った場合
const results = [ {subject: 'japanese', score: 40}, {subject: 'history', score: 70}, {subject: 'math', score: 25}, {subject: 'english', score: 80} ]; let failed = false; for (let i = 0; i < results.length; i++) { if (results[i].score <= 30) { failed = true; break; } }
someを使った場合
const results = [ {subject: 'japanese', score: 40}, {subject: 'history', score: 70}, {subject: 'math', score: 25}, {subject: 'english', score: 80} ]; const failed = results.some(function(result){ return result.score <= 30; });
every
use case → 条件を一つ一つ検証していき全て条件が当てはまるかどうか知りたい時(論理積)
例→全ての教科が50点を超えているかを知りたい。
for文を使った場合
const results = [ {subject: 'japanese', score: 40}, {subject: 'history', score: 70}, {subject: 'math', score: 25}, {subject: 'english', score: 80} ]; let pass = true; for (let i = 0; i < results.length; i++) { if (results[i].score < 50) { pass = false; break; } }
every文を使った場合
const results = [ {subject: 'japanese', score: 40}, {subject: 'history', score: 70}, {subject: 'math', score: 25}, {subject: 'english', score: 80} ]; const pass = results.every(function(result){ return result.score >= 50; });
reduce
use case →配列の中身の合計を求めたい時
for文を使った場合
const numbers = [1, 24, 3, 45, 23]; let sum = 0; for (let i = 0; i < numbers.length; i++) { sum += numbers[i]; }
forEachを使った場合
const numbers = [1, 24, 3, 45, 23]; var sum = numbers.reduce(function (accumulator, number) { return accumulator + number; },0); //0は初期値。
これらのメソッドを使ってみて、良いと思った点
・メソッド名をみただけで何をしようとしているのかが分かる。(for文だと中身の処理をみなければわからない)
・for(let i = 0; array.length < i; i++) ←こいつを書かなくて済む
・for文に比べコード量が少ない
・なんかスタイリッシュでかっこいい
これらのメソッドを使う際に覚えておくこと
・forEach以外のメソッドは必ずreturnを書かなければいけない。
→意外と忘れがち。想定通りに動かない時は、まずはここを疑う。
・コールバック関数の引数の名前は、配列名の単数形にする。
→マストではないが意識してみるといいのかも?