ReasonMLからReasonReactまで
・ReasonMLとは
https://reasonml.github.io/img/reason.svg
Facebook社のcheng lou氏(react-motion作った人)が開発している、OCamlに似たAltJS
OCamlのシンタックスをJSフレンドリーにした感じ
BuckleScriptというコンパイラを使って変換する
強い静的型付けの関数型言語
Reactと一緒に使うことを強く意識して作られている。ReasonReactという公式のライブラリがある
Facebook MessengerはReasonML(ReasonReact)で書かれているらしい
(FlowはOCamlで実装されている)
・なぜReasonMLなのか
コンパイル時に厳密に型チェックが入る
→ コンパイルが通れば、基本的にバグはないという思想
→ コンパイラに従えば、勝手に堅牢なプログラムになっている(はず)
→ 結果として良い作法が身につく
ReactのプロトタイプはSMLで作られていた(ReactML)
→ 関数型、特にML言語との親和性がある
→ ReasonMLはReactと使うことを考えて設計されている
→ ReactやるならReasonMLが最強では?
・インストール
code:install
yarn global add bs-platform
code:create project
bsb -init sample-project -theme basic-reason
・基本文法
リテラル・算術演算子など
code: variable.re
let message = "Hello!"; // イミュータブルな変数宣言
message = "GoodBye!"; // Error: 変更不可
let message = "GoodBye"; // shadowingはできる
let score = ref(10); // ミュータブルな変数宣言(ポインタ変数的なやつ)
Js.log(score^); // 変数へのアクセスには ^ をつける
score := 18; // 変数への代入は :=
・変数は基本イミュータブル
code: function.re
let greet = (name) => "Hello" ++ name; // 関数はアロー関数の形式で宣言
greet("John"); // 呼び出しは普通
let sumTriple = (a, b, c) => {
let sum = a + b + c;
sum * 3 // 最後の式の値がリターンされる
};
let x = sumTriple();
let add = (~x, ~y) => x + y; // 名前付き引数
add(~x=1, ~y=4);
let add = (~name as n, ~message as m) => m ++ " " ++ n; // 名前付き引数に別名をつけられる
code:type.re
let myInt = 5;
let myInt: int = 5;
let myInt = (5: int) + (4: int);
let add = (x: int, y: int) : int => x + y;
let drawCircle = (~radius as r: int) : unit => ...;
// エイリアス
type scoreType = int;
// ジェネリクス的なやつ
type coordinates('a) = ('a, 'a, 'a);
let buddy: coordinates(int) = (10, 20, 20);
// 列挙型的なやつ
type myResponseVariant =
| Yes
| No
| PrettyMuch;
let areYouCrushingIt = Yes;
// 列挙型は値を保持できる
type account =
| None
| Instagram(string)
| Facebook(string, int);
let myAccount = Facebook("Josh", 26);
let friendAccount = Instagram("Jenny");
code:patternMatch.re
// 列挙型を定義
type payload =
| BadResult(int)
| GoodResult(string)
| NoResult;
let data = GoodResult("very good");
// switch文内でパターンマッチが使える
let message =
switch (data) {
| GoodResult(theMessage) => "Success! " ++ theMessage
| BadResult(errorCode) => "Something's wrong. The error code is: " ++ string_of_int(errorCode)
| NoResult => "Nothing"
};
・ReasonReactの導入
code:create project
bsb -init sample-reason-react -theme react-hooks
・ReasonReactの基本
code:Component
let make = (~name) => {
<div>{React.string("Hello, " ++ name)}</div>
};
code:Children
module ComponentTakesChildren = {
let make = (~name, ~children) => {
<div>
<p> {React.string("Hello, " ++ name)} </p>
children
</div>
};
};
・実例
Hooks使ってタイマー作ってみるチュートリアル
code:Time.re
type state = {
seconds: int,
isTicking: bool
};
type action =
| Start
| Stop
| Reset
| Tick;
module Button = {
let make = (~label, ~onClick) => {
<button onClick> {label |> ReasonReact.string} </button>
};
};
let make = () => {
let (state, dispatch) =
React.useReducer(
(state, action) =>
switch (action) {
| Start => {...state, isTicking: true}
| Stop => {...state, isTicking: false}
| Reset => {...state, seconds: 30}
| Tick => state.isTicking && state.seconds > 0
? {...state, seconds: state.seconds - 1} : state
},
{isTicking: true, seconds: 30}
);
React.useEffect(() => {
let timerId = Js.Global.setInterval(() => dispatch(Tick), 1000);
Some(() => Js.Global.clearInterval(timerId))
});
<div>
{ReasonReact.string(
"There are " ++ string_of_int(state.seconds) ++ " on the clock"
)}
{state.isTicking
? <Button label="STOP" onClick={_event => dispatch(Stop)} />
: <>
<Button label="START" onClick={_event => dispatch(Start)} />
<Button label="RESET" onClick={_event => dispatch(Reset)} />
</>
}
</div>
}
Reasonなのでインポートいらない(使ったら勝手にインポートしてくれる
・まとめ・感想
React勉強します!
・その他興味がある技術とか記事とか本とか
・RE:DOM
https://redom.js.org/static/images/redomjs.svg
・Front-end Developer Handbook 2019
・エンジニアの心を整える技術
心理的安全性大事
ArakiTakaki.icon 興味あったのでサンプルリポジトリ作りました