2021年12月24日金曜日

コロナ動向など

 新型コロナウィルス、影響はまだ続きそう

そしてオミクロン株で、さらに感染者が急増しそう。
まだこれが重症者が増えるのか云々・・・まだわからないことが多そう

ただ、感染者が異常に増えること、気管支に影響を及ぼすことがわかっている
ということはかなり、気管支から痛みがひどくなりそうであるし、咳がひどくなりそうだ

インフルエンザでも、気管支に炎症がひどくなると重症化になりそうであるが、
オミクロン株ではどうなのだろう

老若男女を問わず、気管支に影響をすれば、症状がひどくなりそうですが、世界的にはどうなのだろう?疑問点が多そう。


2022年も新型コロナの影響が続きそう
今まで通り、緊張感をもって行動しましょう


猫のようにのんびり過ごしましょう



2021年12月19日日曜日

この3か月

この3か月にはいろいろなことがあり、私用ばかりの日々でした。

先月には母親が亡くなり、田舎が遠くなってしまいました。

本籍だけは田舎のまま、寂しくなりました。


ここ3か月、社会の情勢は大きく変わった。

衆議院議員選挙は、予想通り、自民党が勝利した。
やっていることは進歩がいまいちですが、どこかの党は、悪口ばかりで何もできない
口だけは達者な政党には辟易します

新型コロナはいつの間にかに下火になる
デルタ型、脅威でしたが自然に消滅したかんじです
でも、オミクロン型が登場し、戦々恐々
実体がわからないので何も言えませんが、今まで以上に警戒しながら過ごすのがよさそう


来年から当たらなことをやる計画、ここ10年あし踏み状態でしたので、
これからは前進します。




2021年10月9日土曜日

10月7日の地震

10月7日、寝ようとしていた時に、大きな地震、どんと突き上げた後は横揺れ、物が良くなり、一部不安定なものは落下

プリンタが移動し、PCの上に落下しなかったのが幸い、落下していたら思うとぞっとする
猫達は大きな揺れで、猫ベッドに避難
大きな地震は経験が少ないので、猫たちはパニックになっていたが、その後は落ち着く

翌日の8日、早めに目が覚めると、待ち合わせ場所の駅の路線が運転見合わせ、9時運転再開・・・
待ち合わせ時間が8時10分、遠回りで迂回して徒歩で移動となると、テレビを観て朝食をとった後、即着替えて、出発、6時10分に出発した

最寄駅で18分発車が、20分遅れて出発、その後は徐行運転でのろのろ
西船橋で東西線に乗り換えて、待ち合わせ場所から徒歩30分の駅に到着、
歩き疲れと、電車の混雑度で参る

夜に帰宅後はぐったりです。

地震の翌日に電車の影響が大きとは予想外でした
でも早めに起床していたので対応は可能でした~



2021年10月3日日曜日

夜長の秋

9月で日の出は遅くなり、日の入りが早くなり、10月になると、さらに秋の夜長だ
5時半を過ぎると暗くなりすぎです

感染者数が減り。人出増えている。でも日中のみで、秋の夜長、歩いている人は少ない
やはり、新型コロナウィルスの影響は大きい

ゆっくりと、撮影散策をしたいものですが、来年にならないと、まだ不安がよぎる

心配性なので、ワクチン接種をしたとしても感染には気を付けています
自分で自分を守らないと、大変なことになる

秋の夜長、虫の声を聴きながら月見もよいが、今は未明にならないと月が見えないので寂しい
秋の虫を聴きながら、テレビを楽しむ


先日、私の容姿を観ながら、笑う女性がいました、
京葉線の海浜幕張駅から乗車した若い夫婦、幕張アウトレットの帰りのようだ

いい夫婦ですね。不幸がたくさん訪れることをお祈りいたします。


ミケ、人とは愚かなり


2021年10月2日土曜日

自分で自分をほめよう

9月は精神的に落ち込むことが多く、つらい1か月であった
でもなっとか、1か月を乗り切る、まだ大変なことが続いている

以前の自分なら、負けていた
今回はまだ完全にないとしても、自分で自分をほめてあげたい

無理なことも多かったし、つらい時もあった
精神的に落ち込む日々であった

でもこれだけ辛いことを経験し、自分で乗り切ろうとしていることが、自信にもつながりそうだ
コツコツ努力して日々、過ごすのみ

考えすぎるよりも行動が第一だ

中秋の名月

きれいな月見、自然を見ていると、嫌なことを忘れます


 

2021年9月19日日曜日

With corona

今後の社会は、「With corona」が主体になりそう

ワクチン接種はある程度までは進むだろうが、いずれ停滞する
打ちたくない人、副作用が気になる人は少なからず多いであろう

社会が停滞すれば、国の財政支出をしても赤字になるだけ
経済も停滞し、社会が成り立たなくなってします

今後は感染者が増えても、重症者やなくなる人も減らして、社会を動かすことになりそう
絶対的な薬がないの、どのように行うかは、難しい

やはり、感染対策をしっかりして社会を動かすことが重要だ


  • 感染者の早めに見つける検査体制の拡充
  • 医療体制の拡充
  • 医療体制を補助できる社会の確率
  • ワクチン接種と、抗体、抗原検査体制の拡充


ワクチン接種については副作用などを気にすると、怖いのは確か、私も半年ぐらい考えましたが、接種を行いました

アレルギー体質で、過去のインフルエンザワクチンで副作用がひどかったのでいろいろ考えました。

  • 1回目は、打った箇所の痛みと肩が上がらないのが2日続く
  • 2回目は、1課目と同じ症状で、5日続く

発熱などが気になる人は薬を用意しておく必要があります
アメリカではワクチン接種前に解熱剤を飲むそうですが、日本では発熱後だそうです
どのように考えるかは自由?ですがワクチン接種の副作用を抑えるには接種前に解熱剤を飲んだほうが良いように思える・・・・あくまで個人の見解です


社会は、With coronaとして今後1年、大きく変わりそう
それを考えて行動しましょう


2021年9月5日日曜日

肌寒くなる

8月31日の夜の雨になり、9月になって肌寒い日々となってしまった
最高気温が10度以上、下がり、朝晩はさらにひんやり、生温かい水道水は冷たくなり、顔を洗いやすくなる。

これだけ気温が下がると、体調がおかしくなりそうです
風邪をひかないように気を付けましょう

でも、9月7日以降は最高気温が徐々に上がりそうですが、8月の猛暑は戻ってこないのは安心します
気温が下がると、夏バテ気味の身体にはよく、夜の睡眠が良く取れますし、眠気が強くなっています
この涼しい時に暑さ疲れの身体をよく休めましょう

9月4日に2回目のワクチン接種
夕方から、注した部位が膨らんで痛くなり、肩が上がらなくなってきています
この日は、眠気が強かったので、午後9時過ぎに就寝
ワクチン接種後はよく身体を休養するのがよさそう

発熱のことも考えて薬は準備済みですが、平熱のままです
6日の朝までは様子見で、自宅でゆっくり過ごします

涼しくなり、猫達は温かいところで寝ています
へそ天はしばらく見ることはなさそう

エアコンと扇風機、5日間電源オフ、電気代の節約になりそう



政局運営

官房長官としてはよき菅さん

でも1国の総理としては、リーダーシップが不明だった
新型コロナウィルス対策は誰がやっても難しい問題
その中で、説明しながら次々に対策を行えば、もっと、理解されていたであろう

菅総理のあとは、誰が次期総理になっても混迷するであろう

やるべきことをやりやらないことはやらないのが良い

選挙で言えば、4~6月にやるべきであったし
また、経済との両立で大胆な戦略を踏むべきであった
 経済を動かすには飲食店の大胆な改装などの支援
 医療関係の充実のためにホテルなどの改装
 物資輸送などの充実
などやるべきことを行えば、経済と感染拡大の防止を行えたはず


政局は混迷することがあっても、経済は動く

新型コロナ対策後の経済を見るべきだ
国などの補助金を活かして自らの方向性を変えるべきです


2021年9月1日水曜日

React:React + TypeScript

1.関数コンポーネント

関数コンポーネントです。普通の関数と同じく、引数を型づけしてください。
JSXの要素を返せば戻り値は推論されます。

type AppProps = { message: string }; // interfaceでもよい

const App = ({ message }: AppProps) => <div>{message}</div>;

戻り値を型づけする場合には、JSX.Elementです。
正しい値が返されなければ、エラーが示されます。

const App = ({ message }: AppProps): JSX.Element => <div>{message}</div>;

型エイリアスやインタフェースは定めずに、型注釈を直接書き加えても構いません。
型をほかで使わないときは、この方が簡単です。

const App = ({ message }: { message: string }) =>

<div>{message}</div>;

引数と戻り値をそれぞれ定めるのでなく、関数そのものに型づけすることもできます。

  • コンポーネントの関数をReact.FunctionComponentまたはReact.FCで型づけするのは、TypeScriptの基本テンプレートから除かれるからです。
  • React 18ではReact.FunctionComponentが、デフォルトではchildrenを暗黙で受け取らないように改められるので、将来的にはVoidFunctionComponentは推奨されなくなります。

2.フック

2.1.useState

useStateフックには、可能なかぎり初期値を与えましょう。そうすれば、状態変数の型は推論されるからです。

const [text, setText] = useState('');  // 初期値を与える

初期値を与えなかったとき、「React: フックで値を定めた要素に制御されたコンポーネントを使うよう警告が出る ー Warning: Changing uncontrolled input」という問題も確認されています。

型を組み合わせたいという場合には、useStateにユニオン型をジェネリックで定めればよいでしょう。

const [id, setId] = useState<string | number>(0);

あるいは、型が定めてあっても、初期値があとの初期化処理で決まるとか、値がない場合としてnullを含めたいということもあるかもしれません。そのときも、ユニオン型でnullを加えてください。

const [user, setUser] = React.useState<IUser | null>(null);

// 初期化処理など

setUser(newUser);

######################################

Genericsの簡単な具体例(関数編)

// number型

function test(arg: number): number {

  return arg;

}

// string型

function test2(arg: string): string {

  return arg;

}

test(1); //=> 1

test2("文字列"); //=> 文字列


これをGenericsを使用する事で下記のように書く事が可能です。

test<string>の引数はstring型だけ、またtest<number>の引数はnumber型だけが許されるようになります。

function test<T>(arg: T): T {

  return arg;

}

test<number>(1); //=> 1

test<string>("文字列"); //=> 文字列

//※ Genericsでも型推論ができるので、引数から型が明示的にわかる場合は省略が可能

test("文字列2"); //=> "文字列2"

######################################

nullは型に含めず、useStateの初期値が決まらないという場合には、型アサーションで逃げる手もあります。

const [user, setUser] = React.useState<IUser>({} as IUser);

// 型 'null' の引数を型 'SetStateAction<IUser>' のパラメーターに割り当てることはできません。

// setUser(null);  // nullは認められない

setUser(newUser);  // 型に合致した値のみ設定できる

ただし、型アサーションはTypeScriptに値({})の型を偽っているだけだ、ということにご注意ください。状態変数(user)の値を正しく扱うことは、コードの書き手に委ねられるのです。誤ればランタイムエラーになってしまうかもしれません。

2.2.useReducer

useReducerフックを使うには、リデューサの関数が定められていなければなりません。関数に型づけするのは、リデューサが受け取る状態(state)とアクション(action)のふたつの引数です。戻り値の型は推論されます。

type STORE = { count: number };

type ACTIONTYPE =

    | { type: 'increment' }

    | { type: 'decrement' };

const reducer = (state: STORE, action: ACTIONTYPE) => {

    switch (action.type) {

        case 'increment':

            return { count: state.count + 1 };

        case 'decrement':

            return { count: state.count - 1 };

        default:

            return state;

    }

};


export default reducer;

すると、useReducerフックを使う側では、とくに型の定めはなくて構いません。

import { useReducer } from 'react';

import reducer from './reducer';


const initialState = { count: 0 };

const Counter = () => {

    const [state, dispatch] = useReducer(reducer, initialState);


};

リデューサ関数そのものを、React.Reducerで型づけることもできます。状態(state)とアクション(action)を受け取って、戻り値は状態です。引数の型はジェネリックで与えてください。

import React from 'react';


// const reducer = (state: STORE, action: ACTIONTYPE) => {

const reducer: React.Reducer<STORE, ACTIONTYPE> = (state, action) => {


};

なお、「React + TypeScript: useReducerを使ったカウンターのアプリケーションに型づけする」は、簡単なカウンターの作例をもとに、さらに詳しく解説しました。ご興味がありましたらお読みください。


2.3.判別可能なユニオン型

判別に用いるプロパティが備わった型を複数結ぶと、判別可能なユニオン型(discriminated union)と呼ばれます。

type ACTIONTYPE =

    | { type: 'increment' }

    | { type: 'decrement' };

判別用のプロパティ値が限定されるため、それ以外の値を弾くことができるのです。

const reducer = (state: STORE, action: ACTIONTYPE) => {

    switch (action.type) {

        case 'increment':

            return { count: state.count + 1 };

        case 'decrement':

            return { count: state.count - 1 };

        // 型 '"reset"' は型 '"increment" | "decrement"' と比較できません。

        /* case 'reset':  // エラー

            return { count: 0 }; */

        default:

            return state;

    }

};


2.4.useEffect

useEffectフックでは、はっきりした型づけより、推論される戻り値の型にご注意ください。たとえば、つぎの例です。

useEffect(

     () =>

          window.setTimeout(() => console.log('timeout'), 1000)

     , []

);

アロー関数式=>の本体に波括弧{}なしに1行で書いた文は、そのまま戻り値になります(「アロー関数」の「関数の本体」参照)。ところが、useEffectのコールバック関数は、戻り値はなし(undefined)にするか、「エフェクトのクリーンアップ」関数でなければなりません。そのため、つぎのようなエラーが示されてしまうのです。

Type 'number' is not assignable to type 'void | Destructor'.


クリーンアップ関数がないときは、useEffectのコールバックから値を返さないように注意してください(本体が1行のときは波かっこ{}で括ります)。

useEffect(

    () => {

        window.setTimeout(() => console.log('timeout'), 1000)

    }

    , []

);


2.5.useRef

useRefフックについて、「React+TypeScript Cheatsheets」には型の定めと初期値の与え方で、3つの例が示されています。currentプロパティが書き替えられるか、null値の代入を認めるかどうかが違いです。

// 読み取り専用。

const nullRef = useRef<number>(null);

// 指定した型の値で書き替えられる。nullは不可。

const nonNullRef = useRef<number>(null!);

// 型指定にnullを含める。

const nullableRef = useRef<number | null>(null);


3.イベントハンドラ

イベントハンドラのもっとも簡単な定め方は、要素のイベント属性(onChange)に直に書き加えることです。引数のイベント(event)の型は推論されますので、注釈が要りません。

import React, { useState } from 'react';


function App() {

    const [text, setText] = useState('');

    return (

        <div>

            <input type="text"

                value={text}

                onChange={(event) => setText(event.currentTarget.value)}

            />

        </div>

    );

}


ハンドラ関数(handleChange)を分けて定めると、通常の関数と同じように引数と戻り値を型づけすることになるでしょう(戻り値は推論させても構いません)。

function App() {


    const handleChange = (event: React.FormEvent<HTMLInputElement>): void => {

        setText(event.currentTarget.value);

    };

    return (

        <div>

            <input type="text"

                value={text}

                // onChange={(event) => setText(event.currentTarget.value)}

                onChange={handleChange}

            />

        </div>

    );

}

さらに、ハンドラ関数そのものを(この場合FormEventHandlerで)型づけることもできます。定められるのは、前の例と同じく引数と戻り値の型です。けれど、それぞれをアラカルトで決めるのでなく、セットにした関数の型で示す方がより明確になります。

function App() {


    // const handleChange = (event: React.FormEvent<HTMLInputElement>): void => {

    const handleChange: React.FormEventHandler<HTMLInputElement> = (event) => {


}


2021年8月29日日曜日

React:コンポーネントのライフサイクル

1.Reactのコンポーネント

ReactではUIを構成する要素のことをコンポーネント(Component)と呼びます。

具体的にはボタンやヘッダー、コンテナなどのことです。Reactで開発する利点としてはそれらのUIパーツをそれぞれ細かくコンポーネントに分けておくことで、再描画が必要なものだけに更新を走らせてパフォーマンスをチューニングができます。

2.コンポーネントのライフサイクル

ライフサイクルにはまず、大きく分けて3つの期間があります。

それぞれ順に

Mounting、Updating、Unmountingと呼ばれます。

2.1.Mounting

UIにコンポーネントが描画されるまでの準備期間。

使用できるメソッド:

  • constructor()
  • getDerivedStateFromProps()
  • render()
  • componentDidMount()

2.2.Updating

UIにコンポーネントが表示されていて、基本的にユーザーが操作できる期間。

使用できるメソッド:

  • getDerivedStateFromProps()
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate()

2.3.Unmounting

他のコンポーネントに切り替える前に現在のコンポーネントを破棄するための期間。

使用できるメソッド:

  • componentWillUnmount()

3.ライフサイクルメソッド(基本編)

3.1.constructor()

Mounting時

JSXおよびTSXのフォーマットではまず見かけません。JavaScriptでReactを書く場合にstateの初期化やactionのバインドのために使用します。


3.2.componentDidMount()

Mounting時

1度目のrenderが呼ばれた後に1度だけ呼ばれるメソッドです。この時点ではまだUIに表示されていません。データをフェッチしたり、アニメーションやタイマーをセットする場合はここで行います。このメソッドからはDOMが作成されていますが、直接のDOM操作などライフサイクルを外れる処理は原則避けましょう。


3.3.render()

Mounting/Updating時

コンポーネントの根幹となる、一番呼ばれるかつ必須のメソッドです。ここに書いてあるコードが実際にUIに現れるものになります。

renderはpropsやstateが更新されるたびに呼ばれるため、ここで直接propsやstateを操作する処理を書いてはいけません。新しい関数を定義するのも避けましょう。そしてAPIのように、propsやstateの値が変わっても結果は冪等であるべきです。

※冪等:べきとうは、大雑把に言って、ある操作を1回行っても複数回行っても結果が同じであることをいう概念です


3.4.componentDidUpdate()

Updating時

第一引数に1つ前のprops、第二引数に1つ前のstate、第三引数にsnapshot(後述のgetSnapshotBeforeUpdateの返り値)が入ってきますが、必要なければ省略可能です。これもよく呼ばれるメソッドなため、パフォーマンスを低下させるpropsやstateを更新する処理は最低限にしましょう。また、if文や後述のshouldComponentUpdateで無駄な処理を避けることができます。


3.5.componentWillUnmount()

Unmounting時

現在のコンポーネントを破棄する直前に呼ばれるメソッドで、アニメーションやタイマーを設定していた場合はここで破棄します。そうしないと新しいコンポーネントのサイクルが始まった後も、その分のメモリが開放されないままになってしまいます。ちなみにもうrenderが呼ばれることはないので、ここでpropsやstateを変更しても意味がありません。

4.ライフサイクルメソッド(上級編)

4.1.getDerivedStateFromProps()

Mounting時

これだけはstaticです。第一引数に次のprops、第二引数に前のstateが入ってきます。propsの値によってstateの値を更新したい場合、propsが更新されてrender()が呼ばれる前にstateの更新が必要かどうかをチェックするメソッドです。更新があれば更新後のstate、なければnullを返します。


4.2.shouldComponentUpdate()

Updating時

第一引数に次のprops、第二引数に次のstateを持っており、前のpropsやstateの値やアドレスと比較し、変更がなければfalseを、あればtrueを返します。falseが返るとこのあとのrender()は呼ばれず再描画は行われません。PureComponentを使うと自動的にこの比較を行ってくれるため、自分で書くケースは稀ですが要のメソッドです。


4.3.getSnapshotBeforeUpdate()

Updating時

このメソッドの返り値はcomponentDidUpdateの第三引数に渡ります。具体例に挙げられているようなスクロール位置など、引き継ぎたい値がある場合に使います。


また上記に上げた以外で、エラーをハンドリングしたい場合はcomponentDidCatch()というメソッドが用意されています。

5.使用しないライフサイクルメソッド

補足として、React v16.2までで使用されていて、現在は使用を控えたほうがいいメソッドもここで上げておきます。古い資料ではこれらの記述がありますが、見かけても読み飛ばしてよいです。


5.1.getDefalutProps()

一度だけ呼ばれ、propsが渡されなかった場合に使う値を指定できます。constructorや、TypeScriptではデフォルト値を指定することで解決可能。


5.2.getInitialState()

Mounting時にまず呼ばれ、描画前にstateを変更するためのメソッド。TypeScriptではstateに初期値を指定できるので特に必要性を感じることはありません。


5.3.componentWillMount()

v16.3以降ではUNSAFE_componentWillMount()に改名されており、v17で完全に削除予定。1回目のrenderが呼ばれる直前に実行されます。


5.4.componentWillUpdate()

v16.3以降ではUNSAFE_componentWillUpdate()になっており、これもv17から削除予定です。使いたいと思ったら代わりにcomponentDidUpdate()やgetSnapshotBeforeUpdate()を使用すべき。


5.5.componentWillReceiveProps()

v16.3以降ではUNSAFE_componentWillReceiveProps()で、v17から削除予定。componentDidUpdate()またはgetDerivedStateFromProps()で代用できます。


2021年8月26日木曜日

React:開発手順

 1.準備

簡単なデザインと、JSONデータを準備する。
設計書もよいが、テスト駆動型でかつアジャイルで開発するほうが、よりよいものができる

2.UI をコンポーネントの階層構造にする

モックを形作っている各コンポーネント(構成要素)を四角で囲んで、それぞれに名前をつけていくことです。

JSON のデータモデルをユーザに向けて表示することはよくありますので、モデルを正しく構築されていれば、UI(つまりコンポーネントの構造)にもうまくマッピングされるということが分かるでしょう。これは、UI とデータモデルが同じ 情報の構造 を持つ傾向があるためです。UI を分割して、それぞれのコンポーネントがデータモデルの厳密に一部分だけを表現するよう、落とし込みましょう。

5 種類のコンポーネントがこのアプリの中にあることが見て取れます。

  1. FilterableProductTable(オレンジ色): このサンプル全体を含む
  2. SearchBar(青色): すべてのユーザ入力を受け付ける
  3. ProductTable(緑色): ユーザ入力に基づくデータの集合を表示・フィルタする
  4. ProductCategoryRow(水色): カテゴリを見出しとして表示する
  5. ProductRow(赤色): 各商品を 1 行で表示する

ProductTable を見てみると、表のヘッダ(「Name」や「Price」のラベルを含む)が単独のコンポーネントになっていないことがわかります。

これは好みの問題で、コンポーネントにするかしないかは両論あります。今回の例でいえば、ヘッダを ProductTable の一部にしたのは、データの集合を描画するという ProductTable の責務の一環として適切だったからです。

しかしながら、将来ヘッダーが肥大化して複雑になった場合(例えばソート機能を追加した場合など)は、ProductTableHeader のようなコンポーネントにするのが適切になるでしょう。

さて、モック内にコンポーネントを特定できましたので、階層構造に並べてみましょう。モックで他のコンポーネントの中にあるコンポーネントを、階層構造でも子要素として配置すればいいのです。次のようになります。

  • FilterableProductTable
    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

3.Reactで静的なバージョンを作成する

データモデルを描画するだけの機能を持った静的なバージョンのアプリを作る際には、他のコンポーネントを再利用しつつそれらに props を通じてデータを渡す形で、自分のコンポーネントを組み上げます。

props は親から子へとデータを渡すための手段です。

state はユーザ操作や時間経過などで動的に変化するデータを扱うために確保されている機能です。今回のアプリは静的なバージョンなので、state は必要ありません。

コンポーネントはトップダウンで作っても、ボトムアップで作っても問題ありません。

つまり、高い階層にあるコンポーネント(例えば FilterableProductTable)から作り始めても、低い階層にあるコンポーネント(ProductRow など)から作り始めても、どちらでもいいのです。シンプルなアプリでは通常トップダウンで作った方が楽ですが、大きなプロジェクトでは開発をしながらテストを書き、ボトムアップで進める方がより簡単です。

ここまでのステップを終えると、データモデルを描画する再利用可能なコンポーネントのライブラリが手に入ります。このアプリは静的なバージョンなので、コンポーネントは render() メソッドだけを持つことになります。

階層構造の中で最上位のコンポーネント(FilterableProductTable)が、データモデルを props として受け取ることになるでしょう。元となるデータモデルを更新して再度 ReactDOM.render() を呼び出すと、UI が更新されることになります。このやり方なら、複雑なことをしていないので、UI がどのように更新されて、どこを変更すればよいか、理解できることでしょう。React の単方向データフロー(あるいは単方向バインディング)により、すべてがモジュール化された高速な状態で保たれます。

4.UI 状態を表現する state を決定

UI をインタラクティブなものにするためには元となっているデータモデルを更新できる必要があります。これは React なら state を使うことで実現できます。


適切に開発を進めていくにあたり、そのアプリに求められている更新可能な状態の最小構成を、最初に考えておいたほうがよいでしょう。

ここで重要なのは、DRY (don’t repeat yourself)の原則です。アプリケーションが必要としている最小限の状態を把握しておき、他に必要なものが出てきたら、そのとき計算すればよいのです。

例えば、TODO リストを作る場合、TODO の各項目を配列で保持するだけにし、個数のカウント用に別の state 変数を持たないようにします。その代わりに、TODO の項目数を表示したいのであれば、配列の length を使えばよいのです。


今回は、次のようなデータがあるとする

  • 元となる商品のリスト
  • ユーザが入力した検索文字列
  • チェックボックスの値
  • フィルタ済みの商品のリスト

それぞれについて見ていき、どれが state になりうるのかを考えてみます。

各データについて、考えましょう。

  • 親から props を通じて与えられたデータでしょうか?
    もしそうなら、それは state ではありません
  • 時間経過で変化しないままでいるデータでしょうか?
    もしそうなら、それは state ではありません
  • コンポーネント内にある他の props や state を使って算出可能なデータでしょうか? もしそうなら、それは state ではありません
例で考えると

  • 元となる商品のリストは props から渡されるので、これは state ではありません。
  • 検索文字列とチェックボックスは時間の経過の中で変化し、また、算出することもできないため、state だと思われます。
  • 最後に、フィルタ済みの商品のリストは state ではありません。何故ならば、元となる商品のリストと検索文字列とチェックボックスの値を組み合わせることで、フィルタ済みの商品のリストを算出することが可能だからです。

というわけで、state と呼べるのは次の 2 つです。

  • ユーザが入力した検索文字列
  • チェックボックスの値


5.state をどこに配置すべきか

アプリの各 state について、次の各項目を確認していきます。

  • その state を使って表示を行う、すべてのコンポーネントを確認する
  • 共通の親コンポーネントを見つける(その階層構造の中で、ある state を必要としているすべてのコンポーネントの上位にある単一のコンポーネントのことです)
  • 共通の親コンポーネントか、その階層構造でさらに上位の別のコンポーネントが state を持っているべきである
  • もし state を持つにふさわしいコンポーネントを見つけられなかった場合は、state を保持するためだけの新しいコンポーネントを作り、階層構造の中ですでに見つけておいた共通の親コンポーネントの上に配置する

それでは、例に適用してみましょう。

  • ProductTable は商品リストをフィルタする必要があり、SearchBar は検索文字列とチェック状態を表示する必要がある
  • 共通の親コンポーネントは FilterableProductTable である
  • 概念的にも、検索文字列とチェック状態が FilterableProductTable に配置されることは妥当である

state を FilterableProductTable の中に配置することが決まりました。では早速、インスタンス変数として this.state = {filterText: '', inStockOnly: false} を FilterableProductTable の constructor に追加して、初期状態をアプリに反映しましょう。その次は、filterText と inStockOnly を ProductTable と SearchBar に props として渡します。最後に、これらの props を使って ProductTable のフィルタ処理を行い、SearchBar のフォームにも値を埋めます。


6.逆方向のデータフローを追加

現在のバージョンのサンプルで文字を打ち込んだり、チェックボックスを切り替えてみると、React がその入力を無視することがわかります。これは意図的な挙動で、input の value props が、常に FilterableProductTable から渡された state と同じ値になるようにセットしてあるのです。


それでは、どんな挙動になってほしいのかを考えてみましょう。ユーザがフォームを変更するたびに、ユーザ入力を反映するように state を更新したいですね。コンポーネントの state を更新できるのは自分自身だけであるべきなので、FilterableProductTable は SearchBar にコールバックを渡しておいて、state を更新したいときに実行してもらうようにします。入力のたびに呼び出される onChange イベントを利用するとよいでしょう。このコールバックを実行された FilterableProductTable は、setState() を呼び出し、その結果としてアプリが更新されます。


2021年8月25日水曜日

React:デザインパターン

1.デザインパターンの重要性

デザインパターンとは、ソフトウェア開発において一般的に発生する問題に対する反復可能な解決策のことです。

デザインパターンは基本的なテンプレートとして機能し、与えられた要求に応じてプログラムの機能を構築することができます。


デザインパターンは、開発プロセスを高速化するだけでなく、コードの読みやすさやメンテナンスのしやすさを向上させます。

デザインパターンの一般的な例としては、SingletonパターンやGang-of-Fourパターンなどがあります。


ソフトウェア開発において、デザインパターンには2つの共通した役割があります。

  • 開発者に共通のプラットフォームを提供する

デザインパターンは、標準的な用語や既知の問題に対する解決策を提供する。

  • ベストプラクティスの確保

デザインパターンは、広範な研究とテストの結果として作成されています。デザインパターンは、開発者が開発環境に容易に慣れることができるだけでなく、ベストプラクティスが守られていることを保証します。

その結果、エラーが少なくなり、適切なデザインパターンが実装されていれば簡単に回避できたであろう問題のデバッグや解明にかかる時間を節約することができます。


2.Reactjsの機能

reactは、Githubで公開されているcreate-react-appを使ってインストールできます。npmを使用すると、他のすべての依存関係を追加できます。

React.jsは、JSXを利用しています。これは、JavaScriptの構文拡張です。JavaScriptのフルパワーを備えており、Reactの「要素」と呼ばれるものを提供してくれます。


JSXの使用は必須ではありませんが、JSXが提供する便利な視覚支援とスタイリングオプションのため、好ましい方法です。また、有用なエラーメッセージや警告も表示されます。

React.jsの基本理念は、再利用可能なリアクトコンポーネントです。このコンポーネントベースのアプローチは、Webアプリケーションのリッチなユーザーインターフェースを構築するために活用できることがわかります。

これらのReactコンポーネントは、それ自体が小さなシステムであると考えることができます。各コンポーネントは、独自の状態、入力、出力を持ちます。

コンポーネントの入力は、プロップの形で取得されます。コンポーネントは、ブラックボックスと考えることができます。それぞれが独自の状態とライフサイクルを持っています。コンポーネントは簡単に構成することができます。

最終的なReactアプリは、保守性の高いコードで構成されています。

3.Reactのデザインパターン

3.1.ステートレスコンポーネント

ステートとは、コンポーネントにインポートされるデータのことです。通常、データはデータベースから取得されます。

コンポーネントには、ステートフルコンポーネントとステートレスコンポーネントという2つのタイプがあります。両者の違いは、単にステートがあるかないかだけです。

ステートレスコンポーネントでは、その内部でthis.stateに到達することはできません。

ステートレスコンポーネントは、機能的コンポーネントや提示的コンポーネントとも呼ばれます。Reactでは、このようなコンポーネントは常に同じものをレンダリングするか、propsで渡されたものだけをレンダリングします。

開発者としての目的は、たとえその特定のコンポーネントを再利用しなければならないシナリオがすぐになくても、ステートレスコンポーネントを作成することです。

多くの場合、開発者は、あるコンポーネントが状態を持つ必要があるかどうかを、コードを書き始めてから理解しますが、それは必ずしも事前に明確ではないからです。

階層構造のコンポーネントでは、親コンポーネントにできるだけ多くの状態を保持させ、ステートレスな子コンポーネントを作るのがベストな方法です。データの受け渡しはプロップで行います。


3.2.条件付きレンダリング

条件はソフトウェア開発者の武器の中で最も重要なツールです。

Reactコンポーネントを作成する過程で、状態に応じて特定のJSXコードをレンダリングする必要が生じることがよくあります。これを実現するのが、条件付きレンダリングです。

条件付きレンダリングは、ニーズに応じて個別のコンポーネントを作成し、アプリケーションに必要なものだけをレンダリングすることができるので、非常に便利です。

例えば、条件付きレンダリングを使って、ユーザーのログイン状態に応じて異なるメッセージをユーザーに表示することができます。メッセージは、 isLoggedIn  というプロップの値に従います。


3.3.レンダリングプロップ

デザインパターンが共通の問題を解決するために存在することを説明しました。Reactでは、ロジックの繰り返しの問題を解決するためにRenderプロップが用意されています。

Reactの公式ドキュメントによると、レンダープロップは「値が関数であるプロップを使ってReactコンポーネント間でコードを共有するためのテクニック」と定義されています。

レンダープロップは、異なるコンポーネント間で同じ状態を共有することができるため、非常に便利なものです。各コンポーネント内のロジックをハードコーディングする代わりに、何をレンダリングするかを決定するために関数プロップを使用することができます。

Formik、React Router、Downshiftなど、レンダープロップを利用した人気のあるライブラリがあります。


3.4.制御されたコンポーネント

Webフォームは多くのアプリケーションで共通の要件であり、制御されたコンポーネントはフォームの状態を処理するためのReactの答えです。

コントロールされたコンポーネントは、プロップを通して状態を受け取ります。それは  onChange のようなコールバックによって変更を通知することができます。 親コンポーネントは、コールバックを処理し、自身の状態を管理することで、コントロールされたコンポーネントを制御することができ、その間、新しい値はコントロールされたコンポーネントにpropsとして渡されます。デフォルトでは、Reactフォームは制御されたコンポーネントと制御されていないコンポーネントの両方をサポートしています。制御されたコンポーネントを使用することを強くお勧めします。

次のコードスニペットは、制御されたコンポーネントを示しています。

<input type = "text" value = {value} onChange = {handleChange} />    


3.5.Reactのフック

フックはReactの比較的新しい追加機能で、React 16.8で導入されました。

これらの機能により、開発者はクラスなしでReactを使用することができます。Effect Hook ( useEffect ) や State Hook など、さまざまなフックがあらかじめ用意されています。

利用可能なフックの完全なリストについては、 Hooks API Reference  を参照してください。 Reactにあらかじめ用意されているフックとは別に、独自のフックを作成することもできます。これにより、コンポーネントのロジックを抽出し、再利用可能な関数を作成することができます。


フックはReactの歓迎すべき機能であり、開発者コミュニティはこの新しい機能を非常に熱心に評価しています。

しかし、フックの引数がオブジェクト、配列、関数である場合には、フックの扱いが少し難しくなることがあることを覚えておく必要があります。これでは少々混乱してしまいます。

一方で、カスタムフックは簡単で使いやすく、開発者にとっても大きなメリットがあります。


React:React

1.Reactとは 

JavaScript フロントエンドフレームワーク

アプリケーションで各状態に対するシンプルな設計をすることで、React はデータが変更された時に、適切なコンポーネントだけを効率的に更新してレンダリングすることができる

自身の状態を管理するカプセル化されたコンポーネントを構築することで、それらのコンポーネントを呼び出し複雑なUI もコンポーネント呼び出しで作成できる


2.Reduxとは

Fluxアーキテクチャの一種

2.1.構成用要素

2.1.1.Reduce

状態を変化させる関数

引数

store        今の状態を示すオブジェクト

action        どんな動作を行ったかを示すオブジェクト


ES2015仕様:Spread Operator

const hoge = [23];
console.log(1, ...hoge, 4.5);

// 実行結果 [1,2,3,4,5]


const fuga = { name: 'Taro', age: 25 };
const piyo = { name: 'Jiro', location: 'Tokyo' };
console.log({ ...fuga, ...piyo });

// プロパティがかぶる場合、後のものが優先する
// 実行結果 {name: 'Jiro',age: 25 ,location: 'Tokyo' }


const myFunc = (x, y, z) => [x, y, z];
const age = [012];
mfFunc(...age);

// 実行結果 [0,1,2]


注意点

値渡が基本 オブジェクトや配列は参照渡しとなるため、Object.assignを用いる

onst target = { a: 1, b: 2}
const source = { b: 3, d: 4}

const returnedTarget = Object.assign(target, source);

console.log(target);
console.log(source);
console.log(returnedTarget);

// $ node test.js
// { a: 1, b: 3, d: 4 }
// { b: 3, d: 4 }
// { a: 1, b: 3, d: 4 }


let user = {
    username: "John",
};

let user_id = {
    id: 1,
};

let email = {
    email: "john@example.com",
};

user = Object.assign(user, user_id, email);

console.log(user);

  //結果
  //{ username: 'John', id: 1, email: 'john@example.com' }


Object.assignを使った例(form)

const form = {
    firstName: null,
    lastName: null,
    Email: null,
    zipCode: null,
    Address: null,
    Phone: null
}

const input = {
    firstName: 'John',
    lastName: 'Doe',
    Email: 'john@example.com'
}

Object.assign(form, input)

console.log(form)

// $ node test.js
//  {
//  firstName: 'John',
//  lastName: 'Doe',
//  Email: 'john@example.com',
//  zipCode: null,
//  Address: null,
//  Phone: null
// }


2021年8月24日火曜日

JS:Atomic Design

1.Atomic Designのコンポーネント

Atomic Designで有名なのは、UIの構造を次の5段階で考える

  • Atoms(原子)
  • Molecules(分子)
  • Organisms(有機体)
  • Templates(テンプレート)
  • Pages(ページ)


あらゆるものが原子の集まりでできているように、ページもAtoms(原子)の集まりであると考え、Atomsが組み合わさってMolecules(分子)になり、Molecules(分子)が組み合わさってOrganisms(有機体)となる。

Organisms(有機体)の集まりでページのフレームであるTemplates(テンプレート)を作るが、このTemplatesは具体的なコンテンツの入っていない空っぽのページの枠組み。そこに具体的なテキストや画像を入れ込んでPages(ページ)を作る……というふうに、UIを階層構造で考えます。


1.1.Atoms(原子)の例

Atomsの例は、検索フォームのパーツです。ここでは「ラベル」「テキスト入力欄」「ボタン」というように、これ以上分けられないような単位のUIをAtomとしています。


1.2.Molecules(分子)の例

「ラベル」「テキスト入力欄」「ボタン」といったAtomを組み合わせて作った「検索フォーム」がMoleculeです。


1.3.Organisms(有機体)の例

そして、この「検索フォーム」やその他「メニュー」や「サイトのロゴ」など、他のMoleculeらが集まってできている「ヘッダ」がOrganismです。


1.4.Templates(テンプレート)の例

Organismを組み合わせ、ページの枠組みを構成します。ただ中身はすべてダミーです。これがTemplate。


1.5.Pages(ページ)の例

Templateに具体的なコンテンツを入れ込んだのが、最終的なアウトプットとなるPageです。


このように、UIを分解して考え、他の画面でも共通で使えるAtom、Moleculeをどう設計するか、細部を作りながら全体を俯瞰し、また細部が適切かどうか、具体的にコンテンツを入れながら考えるというのが、Atomic DesignのUIデザイン方法論です。

このようにしてUIを考え、サイト全体として共通のUIライブラリを作り上げます。



React:React + Material-UI

ReactとMaterial-UIを利用した管理画面などを作成することが多くなりました

また、前提としてJavaScriptやTypeScriptの知識があるとより分かりやすいです。


1.アプリの作成

Create React Appで新しいReactアプリを作成します。

npx create-react-app react-material-ui-sample --template typescript        

プロジェクトのディレクトリへ移動して実行します。

cd react-material-ui-sample    

npm start    


2.ディレクトリ構成

ディレクトリはあまりネストさせすぎずシンプルな構造にしました。
コンポーネントの分け方はAtomic Designを参考にしています。

3.ルーティング

ルーティングを実装するためのライブラリをインストールします。

npm install --save react-router-dom    

npm install --save-dev @types/react-router-dom    


4.Material-UIを導入

Reactアプリの準備が出来たので、Material-UIを導入していきます。


4.1.Material-UIをインストール

npm install --save @material-ui/core @material-ui/icons    


4.2.フォントを導入

Material-UIと相性の良いGoogle日本語フォントとフォントアイコンを導入しておきます。public/index.htmlのヘッダーにCDNのURLを追加します。

index.html

<head>

〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜

    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />

    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans+JP&subset=japanese" />

    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />

〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜

</head>

4.3.テンプレートを作成

src/components/templates/にページのテンプレートを作成します。Material-UIが公開しているテンプレートを参考に実装します。

import React from "react";
import clsx from "clsx";
import { createTheme } from "@material-ui/core/styles";
import * as colors from "@material-ui/core/colors";
import { makeStyles, createStyles, Theme } from "@material-ui/core/styles";
import { ThemeProvider } from "@material-ui/styles";
import CssBaseline from "@material-ui/core/CssBaseline";
import Drawer from "@material-ui/core/Drawer";
import Box from "@material-ui/core/Box";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import List from "@material-ui/core/List";
import Typography from "@material-ui/core/Typography";
import Divider from "@material-ui/core/Divider";
import Container from "@material-ui/core/Container";
import { Link } from "react-router-dom";
import MenuIcon from "@material-ui/icons/Menu";
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
import IconButton from "@material-ui/core/IconButton";
import HomeIcon from "@material-ui/icons/Home";
import ShoppingCartIcon from "@material-ui/icons/ShoppingCart";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";

const drawerWidth = 240;

const theme = createTheme({
  typography: {
    fontFamily: [
      "Noto Sans JP",
      "Lato",
      "游ゴシック Medium",
      "游ゴシック体",
      "Yu Gothic Medium",
      "YuGothic",
      "ヒラギノ角ゴ ProN",
      "Hiragino Kaku Gothic ProN",
      "メイリオ",
      "Meiryo",
      "MS Pゴシック",
      "MS PGothic",
      "sans-serif",
    ].join(","),
  },
  palette: {
    primary: { main: colors.blue[800] }, // テーマの色
  },
});

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    root: {
      display: "flex",
    },
    toolbar: {
      paddingRight: 24,
    },
    toolbarIcon: {
      display: "flex",
      alignItems: "center",
      justifyContent: "flex-end",
      padding: "0 8px",
      ...theme.mixins.toolbar,
    },
    appBar: {
      zIndex: theme.zIndex.drawer + 1,
      transition: theme.transitions.create(["width""margin"], {
        easing: theme.transitions.easing.sharp,
        duration: theme.transitions.duration.leavingScreen,
      }),
    },
    appBarShift: {
      marginLeft: drawerWidth,
      width: `calc(100% - ${drawerWidth}px)`,
      transition: theme.transitions.create(["width""margin"], {
        easing: theme.transitions.easing.sharp,
        duration: theme.transitions.duration.enteringScreen,
      }),
    },
    menuButton: {
      marginRight: 36,
    },
    menuButtonHidden: {
      display: "none",
    },
    title: {
      flexGrow: 1,
    },
    pageTitle: {
      marginBottom: theme.spacing(1),
    },
    drawerPaper: {
      position: "relative",
      whiteSpace: "nowrap",
      width: drawerWidth,
      transition: theme.transitions.create("width", {
        easing: theme.transitions.easing.sharp,
        duration: theme.transitions.duration.enteringScreen,
      }),
    },
    drawerPaperClose: {
      overflowX: "hidden",
      transition: theme.transitions.create("width", {
        easing: theme.transitions.easing.sharp,
        duration: theme.transitions.duration.leavingScreen,
      }),
      width: theme.spacing(7),
      [theme.breakpoints.up("sm")]: {
        width: theme.spacing(9),
      },
    },
    appBarSpacer: theme.mixins.toolbar,
    content: {
      flexGrow: 1,
      height: "100vh",
      overflow: "auto",
    },
    container: {
      paddingTop: theme.spacing(4),
      paddingBottom: theme.spacing(4),
    },
    paper: {
      padding: theme.spacing(2),
      display: "flex",
      overflow: "auto",
      flexDirection: "column",
    },
    link: {
      textDecoration: "none",
      color: theme.palette.text.secondary,
    },
  })
);

const Copyright = () => {
  return (
    <Typography variant="body2" color="textSecondary" align="center">
      {"Copyright © "}
      <Link color="inherit" to="/">
        管理画面
      </Link>{" "}
      {new Date().getFullYear()}
      {"."}
    </Typography>
  );
};

export interface GenericTemplateProps {
  children: React.ReactNode;
  title: string;
}

const GenericTemplate: React.FC<GenericTemplateProps> = ({
  children,
  title,
}) => {
  const classes = useStyles();
  const [open, setOpen] = React.useState(true);
  const handleDrawerOpen = () => {
    setOpen(true);
  };
  const handleDrawerClose = () => {
    setOpen(false);
  };

  return (
    <ThemeProvider theme={theme}>
      <div className={classes.root}>
        <CssBaseline />
        <AppBar
          position="absolute"
          className={clsx(classes.appBar, open && classes.appBarShift)}
        >
          <Toolbar className={classes.toolbar}>
            <IconButton
              edge="start"
              color="inherit"
              aria-label="open drawer"
              onClick={handleDrawerOpen}
              className={clsx(
                classes.menuButton,
                open && classes.menuButtonHidden
              )}
            >
              <MenuIcon />
            </IconButton>
            <Typography
              component="h1"
              variant="h6"
              color="inherit"
              noWrap
              className={classes.title}
            >
              管理画面
            </Typography>
          </Toolbar>
        </AppBar>
        <Drawer
          variant="permanent"
          classes={{
            paper: clsx(classes.drawerPaper, !open && classes.drawerPaperClose),
          }}
          open={open}
        >
          <div className={classes.toolbarIcon}>
            <IconButton onClick={handleDrawerClose}>
              <ChevronLeftIcon />
            </IconButton>
          </div>
          <Divider />
          <List>
            <Link to="/" className={classes.link}>
              <ListItem button>
                <ListItemIcon>
                  <HomeIcon />
                </ListItemIcon>
                <ListItemText primary="トップページ" />
              </ListItem>
            </Link>
            <Link to="/products" className={classes.link}>
              <ListItem button>
                <ListItemIcon>
                  <ShoppingCartIcon />
                </ListItemIcon>
                <ListItemText primary="商品ページ" />
              </ListItem>
            </Link>
          </List>
        </Drawer>
        <main className={classes.content}>
          <div className={classes.appBarSpacer} />
          <Container maxWidth="lg" className={classes.container}>
            <Typography
              component="h2"
              variant="h5"
              color="inherit"
              noWrap
              className={classes.pageTitle}
            >
              {title}
            </Typography>
            {children}
            <Box pt={4}>
              <Copyright />
            </Box>
          </Container>
        </main>
      </div>
    </ThemeProvider>
  );
};

export default GenericTemplate;

簡単に記載している



2021年8月22日日曜日

JS:Babel

1.Babelとは

Babel(読み方:「バベル」)は、次の世代のJavaScriptの標準機能をブラウザのサポートを待たずに使えるようにするNode.js製のツールである。次の世代の標準機能を使って書かれたコードを、それらの機能をサポートしないブラウザでも動くコードに変換する。

JavaScriptのコードを新しい書き方から古い書き方に変換するツールである。
具体的には、JavaScriptの言語仕様であるES2015以上の仕様のJavaScriptで記述すると、古いブラウザでは動作しない。そこで、Babelを使ってES2015・ES2016といった仕様で記述したJavaScriptファイルを互換性のあるEXMAScript5に変換する。

主に、es2015以降の新しい構文をes5の構文に変換するのに利用されています。もちろん、設定によってはes2018→es2015といった記述方法も可能です。その他にも、ReactのJSXやTypeScriptの変換にも使われます。

2.インストール

package.jsonがある場所で以下のコマンドを実行する。babel-cliはbabelをcliで実行するための本体モジュールで、babel-preset-envはES6の内容をES5に変換する情報のようなもの。

npmで三つのパッケージをインストールします。

$ npm install @babel/core @babel/cli @babel/preset-env --save-dev

@babel/core: Babel本体

@babel/cli: コマンドライン操作用

@babel/preset-env: 変換内容設定用


3..babelrcによる設定

Babelはそのままでは何も変換してはくれないので、どのように変換するのかを事前に設定します。作業フォルダのルートに.babelrcを作成し、JSON形式で設定情報を追記していきます。

{

  "presets": ["@babel/preset-env"]

}


4.プリセット(Presets)の基本

プリセットは、Babelが変換処理を行う際に利用するプラグインのコレクションです。設定情報を基に、コンパイルに必要なプラグインのリストをBabel本体に渡す役割をしているそうです。公式では下記4つのプリセットが用意されています。その他にもいろいろ開発されています。

  • @babel/preset-env: ECMAScript用
  • @babel/preset-flow: Flow用
  • @babel/preset-react: React用
  • @babel/preset-typescript: Typescript用


利用したいプリセットをインストールした後、配列で名前を指定します。後ろから順に適用されます。下記のケースでは、typescript → react → env の順で実行されます。

{

  "presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"]

}

各プリセットにて詳細な設定をしたい場合は、配列で囲みます。0番目に名前、1番目に設定情報です。

{

  "presets": [

    ["@babel/preset-env", {<@babel/preset-envの設定値>}],

    "@babel/preset-react",

    "@babel/preset-typescript"

  ]

}


4.1.@babel/preset-env

@babel/preset-envは、出力したいECMAScriptのバージョンを指定するためのプリセットです。基本的には、サポートしたい範囲(ブラウザバージョンやブラウザシェア、サポートの可否など)を指定します。指定内容に応じて適切なバージョンのJSに変換されるようにしてくれます。特に何も指定しない場合は、一律es5の構文に変換されます。

下記の設定は、Chrome40以上・iOS10以上をサポート対象とした場合です。es5で出力されました。


{

  "presets": [

    ["@babel/preset-env", {

        "targets": [

          "chrome 40",

          "iOS 10"

        ]

      }

    ]

  ]

}

cover 80% in JPは、ブラウザシェア率を基に日本で80%のユーザをカバーするという指定です。es5で出力されました。モダンブラウザの新しいバージョンを指定すると、es2015以降のバージョンで出力されます。


4.2.PolyfillとuseBuiltInsオプション

初期設定では、@babel/preset-envが行うのは構文の変換のみです。Promiseやgeneratorなど、新たに追加された機能の変換には対応していません。オプションで、useBuiltInsにusageを指定すると、必要に応じてPolyfill(代替コード)に変換してくれます。(初期値はfalse)

{

  "presets": [

    ["@babel/preset-env", {

        "targets": [...],

        "useBuiltIns": "usage"

      }

    ]

  ]

}


@babel/polyfill

2019年2月現在、「useBuiltIns:'usage'」の項目には「experimental(実験的)」とあります。お使いの環境でうまく動かなかった場合は、@babel/polyfillと「useBuiltIns:'entry'」の合わせ業もあります。


@babel/polyfillをインストール

$ npm install @babel/polyfill --save

アプリ(サイト)内の一箇所にだけ、下記インポート文を記述します。複数個所に記述するとエラーとなるそうです。この記述は、必要に応じて個別のpolyfillのインポート文に書き換えられます。


// 記述する内容

import "@babel/polyfill";


// 最終的に個別のimport文に変換される

import "core-js/modules/es7.string.pad-start";

import "core-js/modules/es7.string.pad-end";


4.3.設定ファイルをpackage.jsonにまとめる

設定ファイルを増やしたくない場合は、package.jsonにまとめることも可能です。babelという項目を追加します。記述方法は.babelrcの場合と同様です。またwebpack同様、コマンドをscriptsに登録して利用することも可能です。


{

  "name": "sample",

  "version": "1.0.0",

  "main": "index.js",

  "scripts": {

    "build": "babel ./src/index.js --out-file ./dist/index.js"

  },

  "devDependencies": {

    "@babel/cli": "^7.2.3",

    "@babel/core": "^7.2.4",

    "@babel/preset-env": "^7.3.4",

    "webpack": "^4.29.6",

    "webpack-cli": "^3.2.3"

  },

  "babel": {

    "presets": ["@babel/preset-env", {

        "targets": [...],

        "useBuiltIns": "usage"

      }

    ]

  }

}

以上がBabelの基本(の一部)となります。設定方法一つとっても手段が多種多様で迷います。。。