🍎

【React】これ知っトク🐾

2022/02/22に公開

アクションが発生する度に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。

詳しくはこちら👇
https://zenn.dev/oreo2990/articles/98a6444225d817

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