Semantic UI React
「Reading Sinatra」 を読んでいます
世田谷区池尻で週に一度、おいしいランチを食べながら読書会をする、というスタートを切った Ikejiri.rb ですが、 メンバーのいろんな事情に柔軟に対応した結果、 現在は2週間に一度、オンラインで読書会をしています。 メンバーも4人に増えました!
2月から、「Reading Sinatra」を読んでいます。
#ikejirirb のオンライン読書会で @GhostBrain さんの Reading Sinatra を読みはじめたのですが、読んだだけだと次の会までに忘れるので、手書きしながら復習してました pic.twitter.com/vIfDDpzg2s
— かとりえ (@katorie) 2020年2月29日
2週間に一度なので、読書会だけの時間だと前回分を思い出すのに時間がかかったり、 その時間内に「なんとなくわかった」で終わってしまったりするので、 2回分をひとりでスケッチノートしてました。
せっかくなので、ここに全部貼っておきます。
間違っているところあったら教えてください。。
コンポーネントとProps・もう一度環境構築
コンポーネントとProps
React では、データは必ず親コンポーネントから子コンポーネン トへ一方通行で渡されます。下の階層から上の階層にデータの変更を反映させることはできないの
親コンポーネントから子コンポーネントのデータの受け渡しに使われるのが Props
もう一度環境構築
「Props をコンポーネントに受け渡す」にさしかかり、写経してみようと思ったのでいったん環境構築に戻ります。
>> npx create-react-app chapter07 --typescript Creating a new React app in /path/to/chapter07. The --typescript option has been deprecated and will be removed in a future release. In future, please use --template typescript. Installing packages. This might take a couple of minutes. Installing react, react-dom, and react-scripts with cra-template-typescript... yarn add v1.22.0 [1/4] 🔍 Resolving packages... [2/4] 🚚 Fetching packages... error @typescript-eslint/eslint-plugin@2.19.2: The engine "node" is incompatible with this module. Expected version "^8.10.0 || ^10.13.0 || >=11.10.1". Got "11.1.0" error Found incompatible module. info Visit https://yarnpkg.com/en/docs/cli/add for documentation about this command. Aborting installation. yarnpkg add --exact react react-dom react-scripts cra-template-typescript --cwd /path/to/chapter07 has failed. Deleting generated file... package.json Deleting generated file... yarn.lock Deleting chapter07/ from /Users/katorie/js_ex Done.
Fetching packages...
でエラーが起きました。
error @typescript-eslint/eslint-plugin@2.19.2: The engine "node" is incompatible with this module. Expected version "^8.10.0 || ^10.13.0 || >=11.10.1". Got "11.1.0"
とあるので、 node のバージョンが問題になっている。。
現在のバージョンは v11.1.0 なので、nodenv でバージョンを切り替えて再度実行。
// とりあえずエラーの要件を満たすバージョンがすでに入っていたのでこちらを利用 >> nodenv local 12.1.0 // さっきwarning出てたのでオプションの書き方を修正 >> npx create-react-app chapter07 --template typescript
成功しました :tada:
まだ書き方とか考え方に慣れないので、サンプルコードを持ってきて動かしてみるより、 写経しながら進めようと思います。
ReturnType・JSX・ESLint
昨日宣言したポモドーロテクニック作戦はあっさり敗北しました。。 今日はこのアプリを入れて実践してみようと思います↓
apps.apple.comスタートするときにタスクを入力するので「よし!」という気持ちになりそう。
ReturnType
TypeScriptは型推論を行うけれど、その推論した戻り値の型を抽出する方法。
const aloha = () => 'Aloha!' type Greeting = ReturnType<typeof aloha>; const chao = () => Greeting => 'Chao!';
- 複数の関数の戻り値型をまとめて共用体型をつくりたいとき
- ReduxをTypeScriptで使うとき
JSX
JSXはテンプレート言語ではない!
「React の開発者は DOM のインタラクティブな書き換えという複雑な問題に対応するため、アプリ を独立性の高いコンポーネントという単位に分割し、そこにロジックとデザインを完結させて閉じ込 める方法を採った。ひとつのページを役割別に MVC の 3 つに分けて処理するよりも、見た目と機能 が完結した無数のコンポーネントを組み合わせていくほうが、より複雑なアプリケーションを破綻なく構築できると思わない? 前にもちょっと説明したけど、React では各コンポーネントはロジックレベルでもデザインレベルでもそれぞれ相互に独立していて、処理が終わったものから五月雨的にレ ンダリングされていくの」
なるほど。
JSX でタグを階層化して書くときは、ツリー階層のトップレベルはひとつにしないといけない。
ESLint
TSLintはESLintに統合されていくので、今後はTSLintで。
VSCodeの settings.json
に下記を追加しておくとよい。
"editor.codeActionsOnSave": { "source.fixAll.eslint": true },
型のバリエーション
ポモドーロテクニックは25分間集中して5分休憩する、ということだけど、25分ってけっこうあっという間だよなーと思っていた。 今日「50分集中して10分休憩」というソリューションを教わったので、昼間さっそく実践してみようと思う。 ちなみに朝活も50分間。
さて今日もがんばりましょう!!
型のバリエーション
・ number ・ string ・ boolean ・ symbol ・ null ・ undefined
0、’’(空文字)、null、undefined が false、それ以外は true
strictNullChecks オプションを有効にすると、厳密な Null 安全性を保証する。(tsconfig.json で設定する)
VSCodeだと、任意の変数の上にカーソルをホバーさせたときにポップアップで型を教えてくれる!
never
const greet = (friend: 'serval' | 'caracal' | 'cheetah') => { switch (friend) { case 'serval': return 'Hello, Serval!'; case 'caracal': return 'Hello Caracal!'; case 'cheetah': return 'Hello Cheetah!'; default: const check: never = friend; } }; console.log(greet('serval')); // Hello, Serval!
このコードから case 'cheetah
ではじまる2行を削除すると、コンパイルエラーが起きる。
配列とオブジェクト
型は合成できる
interface Foo { hoge?: number, fuga: string }; interface Bar { hoge: number }; interface Buz { piyo: string }; type FooBar1 = Foo & Bar; // 交差型 type FooBar2 = Foo | Bar; // 共用体型 type FooBuz1 = Foo & Buz; type FooBuz2 = Foo | Buz;
Reactではコンポーネントの引数の型合成を行うことが多い。 同じ名前で複数回定義すると、上書きではなく継承されていくので注意。 拡張したいときは、型合成を行ってType Alias で穴めをつけるやり方がおすすめとのこと。
constで変数を定義した場合、変数自体の再代入はできないが各要素の上書きや追加はできる。 配列やオブジェクトの中身までイミュータブルにしたい場合、readonly をつける。
const arr1: ReadonlyArray<string> = ['foo', 'bar']; const arr2: readonly string[] = ['foo', 'bar'];
高階関数・クロージャ・ジェネレータ・カリー化と関数の部分適用
高階関数
// 引数に関数をとる arr = [1, 2, 3] arr.map(n => n * 2); // 戻り値として関数を返す const hof = (ex, fn) => { retrun n => fn(n + ex); }; const plusOneDouble = hof(1, n => n * 2); console.log(plusOneDouble(4)); // (4 + 1) * 2 = 10 // returnを省略して書くと const hof = (ex, fn) => n => fn(n + ex);
クロージャ
const counterMaker = (initialCount) => { let c = initialCount; const increment = () => c++; return increment; }; const count = countMaker(1); console.log(count(), count(), count()); // 1 2 3
countMakerの環境の中で実行されているから変数cの値が毎回リセットされることなく蓄積されていく。
ちなみにクロージャは必ずしも関数を返す必要はない。 あくまでクロージャとは、単に親関数スコープの変数を参照する関数のこと。
ジェネレータ
値を保持しつつ繰り返し処理や逐次処理を行うための手段。
function* rangeGenerator(end, start = 0) { let n = 0; for (let i = start; i < end; i++) { n += 1; yield i; } } const gen = rangeGenerator(3); console.log(gen.next()); // { value: 0, done: false } console.log(gen.next()); // { value: 1, done: false } console.log(gen.next()); // { value: 2, done: false } console.log(gen.next()); // { value: undefined, done: true }
これは??? 使いどころがちょっとわからない!
カリー化と関数の部分適用
ネストした関数。
const multi = (n, m) => n + m; console.log(multi(2, 4)); // 8 const curriedMulti = n => { return m => n * m; } console.log(curriedMulti(2)(4); // 8 const simpleCurriedMulti = n => m => n * m; console.log(simpleCurriedMulti(2)(4)); // 8
ひとつめの関数は今まで見てきたものと同じ。 ふたつめは、nを引数に取り、mを引数にとってnとmの積を返す関数。 関数がネストしているので、引数を渡すかっこがふたつ必要になる。 みっつめは単にreturnを省略したもの。
カリー化された関数の一部の引数を固定して新しい関数をつくることができる。 「関数の部分適用」という。
const multi = n=> m => n * m; const triple = multi(3); console.log(triple(5)); // 15
ちょっと関数型プログラミングと仲良くなれたような気持ち!
便利な配列やオブジェクトのリテラル・非同期処理・コレクションの反復処理・関数型プログラミングの概要
朝活が成功するとブログ更新ができるぞ!として、モチベーションを維持。
便利な配列やオブジェクトのリテラル
// 分割代入 const [n, m] = [1, 4]; // スプレッド構文 const arr1 = [ 'A', 'B', 'C' ]; const arr2 = [...arr1, 'D', 'E' ]; // [ 'A', 'B', 'C', 'D', 'E' ] const obj1 = { a: 1, b: 2, c: 3 }; const obj2 = {...obj1, d: 4, e: 5 }; // { a: 1, b: 2, c: 3, d: 4, e: 5 } // プロパティ名のショートハンド const foo = 65536; const obj = { foo, bar: 4096 }; // { foo: 65536, bar: 4096 }
非同期処理
ES6 から導入された Promise 構文だと↓
const sleep = ms => new Promise(resolve => setTimeout(resolve, mis)); const greet = () => { consoloe.log('おやすみ') sleep(2000) .then(() => { // 2000sec たったあとの処理 }) .catch(err => { // エラー処理 }) } greet();
sleep() 関数が Promise クラスオブジェクトを返して、 then() のメソッドチェーンでつなぐ。then() は複数つなぐこともできる。
finally
で例外のあるなしにかかわらず最後にかならず実行。
ES2017から導入された async/awasit
という構文だと↓
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); const greet = async() => { console.log('おやすみ'); try { await sleep(2000); // 処理 } catch (err) { // エラー処理 } } greet();
async
で定義した Async 関数は、本文中に await
を前置きすることで、他の Async 関数の実行結果を待つようになる。
Async 関数は暗黙のうちに Promise オブジェクトを返している。
コレクションの反復処理
関数型プログラミングについては経験がない。。 入力に対して同じ作用と同じ出力が保証されていること、が関数型プログラミングの良さ。これを参照透過性という。
const arr = [ 1, 2, 3, 4, 5, 6, 7, 8]; arr.map(n => n * 2); arr.filter(n => n % 3 === 0); arr.find(n => n > 4); arr.every(n => n != 0); // すべての要素が条件を満たすかを真偽値で返す arr.some(n => n > 8); // 条件を満たす要素がひとつでもあるかを真偽値で返す arr.includes(5); // 指定した要素が含まれるかを真偽値で返す arr.reduce((n, m) => n + m); // 配列の要素を、与えた式で畳み込んだ値を返す arr.sort((n, m) => n > m ? -1 : 1); // 与えられた比較関数(戻り値が -1: 前に移動、0: 移動しない、1: 後ろ に移動)によって並べ替えた新しい配列を返す
元の配列をいっさいいじらずに、新しい配列を生成して返す。
関数型プログラミングの概要
const arr = [ 1, 2, 3, 4, 5, 6, 7, 8]; const double = n => n * 2; arr.map(double) // arr.map(n => n * 2); と同じ結果
- 無名関数
- 変数に関数を代入できる(つまり、無名関数に名前をつけることができる)
- 高階関数(関数の引数に関数を渡したり、戻り値として関数を返す)
- 部分適用(関数に特定の引数を固定した新しい関数をつくる)
- 複数の高階関数を合成してひとつの関数にできる
:thinking: