【React】これ知っトク🐾
アクションが発生する度にstateの状態をコンソールに出す
steteを出力するミドルウェアを定義して、createStateに設定。
サンプル(例:sagaのミドルウェアと試験用ロガーを同時に利用)
// デバッグ用ロガーミドルウェア
const loggerMiddleware = storeAPI => next => action => {
console.log('dispatching', action)
let result = next(action)
console.log('next state', storeAPI.getState())
return result
}
const store = createStore(
reducer,
// applyMiddleware(sagaMiddleware)
applyMiddleware(loggerMiddleware, sagaMiddleware)
)
呼び出し側はコンポーネントの内部実装を知らなくても良い
コンポーネントを呼び出す側が知っていなければならないのは、
コンポーネントの名前
ファイルパス
props として渡す値
です。
ループ
配列をループで処理する場合。
なるべくforEach、for of、forを使わずに書けないか検討する。
map
配列から、処理した結果の配列を得るような場合、mapを使用する
const idArray = objectArray.map((item) => { return item.id;});
filter
配列から、条件に合うものの配列を得るような場合、filterを使用する。
const filterdArray = objectArray.filter((item) => { return item.value > 0;} );
find
配列から、条件に合う1件を抽出するような場合、findを使用する。filterは合致するものの配列になるが、findは最初に見つかった1件。
const zeroObject = objectArray.find((item) => { return item.value === 0;} );
reduce
配列の各要素を比較して1件抽出するような場合、reduceを使用する。
const maxObject = objectArray.reduce(
(prev, current) => {
return (prev.value > current.value) ? prev : current;
}
);
every
配列が全て条件を満たすかを判定する場合、everyを使用する。
全てのdeletedがnullならture。
const result = objectArray.every((item) => { item.deleted === null });
some
配列のうち一つでも条件を満たすか判定する場合、someを使用する。
deletedがnullのものが一つでもあればtrue。
const result = objectArray.some((item) => { item.deleted === null });
forEach
どれでも簡潔にかけない場合、結果で何かをしない場合など。
forEachの中で、breakは行えない。コールバックなので、returnをした場合はcontinueに相当する。
objectArray.forEach((item) => {
method(item);
});
for of
forEachはbreakが出来ないため、breakが必要な場合はfor ofを使用する。
for (const object of objectArray) {
if (object.flg) {
break;
}
method(object);
}
ネストについて
なるべくネストが浅くなることを常に心がける。
for (const object of objectArray) {
if (flg) {
なんらかの処理;
}
}
のような処理は
for (const object of objectArray) {
if (!flg) {
continue;
}
なんらかの処理;
}
と書いたほうが、処理部分のネストが一段浅くなる。
Promise、async、await
Promise
nodeはコールバックにより、非同期処理が書けることがウリであったが、記述が難解になりがちだったので、生み出されたのがPromise。
Promiseオブジェクトを返すメソッドを実装することにより、処理のチェーンが書きやすくなる。
const myPromise = () => {
return new Promise((resolve, reject) =>{
if (isError) {
reject('Error');
} else {
resolve('Hello Promise');
}
};
};
myPromise()
.then((response) => {
})
.catch((error) => {
});
myPromiseの処理が終われば、thenの処理が行われることになる。
resolveされた場合は、thenのresponseにresolveされた値が入り、rejectされた場合は、catchのerrrorにrejectされた値が入る。
注意
then,catchの中身は、コールバックメソッドなので、この中でreturnしても、元のメソッドからreturnするわけではない。
const myFunc = () => {
const result = myPromise
.then((response) => {
return response;
})
.catch((error) => {
return error;
});
}
上の例で、returnしているが、myFuncから抜けるわけではなく、myPromiseの戻り値としてresultに格納される。catchの場合も同様。
async, await
Promiseの記述も、従来の言語からすると独特だったため、さらに記述しやすくしたのがasync、await。
詳しくはこちら👇
const myPromise = async () => {
if (isError) {
throw('Error');
} else {
return 'Hello Promise';
}
};
const myFunc = async () {
let response;
try {
response = await myPromise();
} catch(error) {
}
}
asyncメソッドは、処理の終了を待たない。待つ場合はawaitを記述する。awaitを使うためには、asyncメソッドである必要がある。
実態はPromiseのため、asyncメソッドでのreturnはresolveであり、throwはrejectである。
asyncメソッドはPromiseと同様.thenや.catchでチェーンができる。
Promiseとasync,awaitが混在すると混乱するので、基本はasync,awaitで書いたほうがよい。
注意
const myFunc = async () {
let response;
try {
response = myPromise();
} catch(error) {
}
}
待つべき箇所でPromiseに対するawaitを忘れると、値が入らないまま先に進んでしまう。
上の例だとresponseの値は不定。
Promise.all
複数のAPIを呼び出して、結果をまとめるような場合、Promise.allを使用する。
const getResult = () => {
return Promise.all([
myPromiseA(),
myPromiseB(),
]).then((results) => {
}).catch((error) => {
});
};
Promiseメソッド(asyncメソッド)を、Promise.allの引数として配列で渡す。
全てのPromiseメソッドが正常終了した場合、then節が実行される。resultsは配列で、Promise.allで指定したメソッドの結果が順番に格納される。
Promiseメソッドが一つでもrejectした場合、catch節が実行される。
export
モジュールのexportはザックリ3種類
export 文は、指定したファイル (またはモジュール) から関数、オブジェクト、プリミティブをエクスポートするために使用
importする際に指定がなければそのクラスや関数を呼ぶもの
importする際にdefault以外のクラスや関数を呼び出したいときは、{}でクラスやファイル名を指定して呼びだすことができる。
export これをつけると、別のファイルから呼び出せるよ!!
ついてなかったら、別のファイルから呼び出せないよ! Errorになるよ!!
メソッドをexport
const testFunction2 = () => {
};
const testFunction2 = () => {
};
module.exports = {
testFunction1,
testFunction2,
};
メソッドを公開したいだけならこれ。
classをexport
module.exports = class TestClass {
constructor(parameter) {
this.parameter = parameter;
}
classMethod() {
console.log(this.parameter);
}
};
classとしてexportする場合。
インスタンスとして、リソースを保持したい場合はclass化する。
特にリソースを保持しない場合は、class化するメリットはあまりない。同レベルの処理がclassで実装されていたら揃えるぐらい。
newをexport
class TestClass {
constructor(parameter) {
this.parameter = parameter;
}
classMethod() {
console.log(this.parameter);
}
};
module.exports = new TestClass();
シングルトンならこれ。nodeの仕組みとしてrequireしたものはパスをキーとしてキャッシュされるため、newが行われるのは一度だけ。
constructor内で分岐している場合は、constructorのテストは出来なくなってしまうため、classのexportにしたほうがいい。(newが行われるのが一度だから)
require
exportされているものを取り込む。ファイルのパスをキーにキャッシュされるため、同一アプリケーション中、同じファイルの取り込みは一度だけ。
const axiosBase = require('axios');
'axios'がexportしている全てが、'axiosBase'に反映される。
routerメソッド
exporessでrouterを記述する場合、よく以下のような書き方をする。
const express = require('express');
const router = express.Router();
const controller = require('../controllers/TestController');
router.get('/test', controller.getMethod);
module.exports = router;
この時のgetMethodは何故かstaticメソッドとして扱われる。
controllerをclassとして実装しても、getMethodからthisの参照が出来ない。→なのでcontrollerをclassとして実装するメリットはない。
Discussion