現在是速度至上的時代,我們必須以一敵百。才能立於不敗之地。
面對越來越複雜的業務邏輯,我們只能全速向前衝,這一切都需要有技術作爲保障。所以我們需要選擇一個能夠實現快速開發的技術。
reason react 網址
個人選擇並且推薦使用 reason 來開發
極速開發 React — Reason 1
- 更安全,更簡潔的方式去構建 React 組件
- 完全兼容 JSX
- 類型安全兼容 javascript 編寫的組件
- 用於一種全新的表述型 API 來描述狀態管理
搭建項目
npm install -g bs-platform
bsb -init my-react-app -theme react
cd my-react-app && npm install && npm start
npm run webpack
創建 index.html
我們將架構默認的工程文件都刪除,自己來寫一個列表的 demo。先創建一個 index.html。
- 引入 Index.js 最終 webpack 打包後會引用 index.js
- id 爲 app 的 div,我們的應用都寫在這個 div 下面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Zidea ReasonReact Examples</title>
</head>
<body>
<div id="app"></div>
<script src="Index.js"></script>
</body>
</html>
然後創建 re 結尾的 reason 文件
ReactDOMRe.renderToElementWithId(<TutListComponent />, "app");
我們這裏可能需要使用 bs-json 和 bs-fetch,我們可以用 npm 來安裝一下這兩個庫,或者說是 reason 的模塊。然後需要 bsconfig 文件添加依賴,這樣我們就可以在工程中使用這兩模塊。
"bs-dependencies": [
"reason-react",
"@glennsl/bs-json",
"bs-fetch"
],
我這裏用 python flask 寫了一個服務,返回值爲
- 我們先定義一個數據結構,用 type 定義 tut 類型 string
我們可以定義 type 定義的數據類型,reason 是一種類型的語言,這對沒有類型的 javascript 是一個強大的支持。
type tut = {title:string, body:string}
我們這裏根據官網的 demo 就先簡單地定義爲 string
type tut = string;
- reason react 給我們提供兩種創建組件模板
- statelessComponent
- reducerComponent
這裏我們創建 reducerComponent 類型組件
- 創建 state 狀態 這也是 ocaml 的語法,應該算是類型匹配吧,有了這個就可以保證我們在做分支語句不會漏掉某些可能性。action 定義方式也是一樣,有關 action 和 state 如果大家還沒有接觸過可以看一看 redux,以後我會分享的。
type state =
| Loading
| Loaded(array(tut))
| Error;
- 定義模塊 Decode
我們可以在模塊定中定義類型和方法,這裏我們定義了一個 tuts 的方法,用於解析服務端返回的數據,然後我們使用 Json 模塊的 Decode 方法,這個 Json 模塊需要我們手動引用一下。|> 如果用過 linux 的腳本或者寫過 powershell 的程序員可能不會陌生,這是鏈式操作。我們接受返回 json -> 然後獲取 messages 字段的值類型爲 string 的數組 -> 然後對數組進行映射。
module Decode = {
let tuts = json: array(string) =>
Json.Decode.(
json |> field("messages",array(string)) |> Array.map(_, tut => tut)
)
}
- **make**
是讓我們在編譯時生產 component 的方法。
- 初始化我們 state
initialState: _state => Loading,
然後就是 reducer 這純函數,最近然後 mvi 模式,再次開始研究 reducer,reduce 我還是在學習 redux + react + rxjs 時學習過,爲了理解也花費不少精力。這裏簡單介紹一下,畢竟 reduce 不是我們今天的重點。reduce 是一個純函數,接受 action(動作)返回一個新的 state。然後我們 reducer 中根據 action 進行分支更新我們狀態。這裏我發現沒有用引入 redux 卻做了 redux 事情,代碼表意也挺好,給 reason 一個贊。
- 在說一下 Promise ,對於瞭解 es6 前端 promise 應該不是很陌生,這裏同樣使用管道符來進行處理。
Js.Promise.(
Fetch.fetch("http://localhost:4600/get_tuts")
|> then_(Fetch.Response.json)
|> then_(json =>
json
|> Decode.tuts
|> (tuts => self.send(TutsFetched(tuts)))
|> resolve
)
|> catch(_err =>
Js.Promise.resolve(self.send(TutsFailedToFetch))
)
|> ignore
)
- 最後就是 render 函數來渲染我們組件到界面
type tut = string;
type state =
| Loading
| Loaded(array(tut))
| Error;
type action =
| TutsFetch
| TutsFetched(array(tut))
| TutsFailedToFetch;
module Decode = {
let tuts = json: array(string) =>
Json.Decode.(
json |> field("messages",array(string)) |> Array.map(_, tut => tut)
)
}
let component = ReasonReact.reducerComponent("TutListComponent");
let make = _children => {
...component,
initialState: _state => Loading,
reducer: (action, _state) =>
switch (action) {
| TutsFetch =>
ReasonReact.UpdateWithSideEffects(
Loading,
(
self =>
Js.Promise.(
Fetch.fetch("http://localhost:4600/get_tuts")
|> then_(Fetch.Response.json)
|> then_(json =>
json
|> Decode.tuts
|> (tuts => self.send(TutsFetched(tuts)))
|> resolve
)
|> catch(_err =>
Js.Promise.resolve(self.send(TutsFailedToFetch))
)
|> ignore
)
),
)
| TutsFetched(tuts) => ReasonReact.Update(Loaded(tuts))
| TutsFailedToFetch => ReasonReact.Update(Error)
},
didMount: self => self.send(TutsFetch),
render: self =>
switch (self.state) {
| Error => <div> (ReasonReact.string("An error occurred!")) </div>
| Loading => <div> (ReasonReact.string("Loading...")) </div>
| Loaded(tuts) =>
<div>
<h1> (ReasonReact.string("tuts")) </h1>
<p> (ReasonReact.string("Source: ")) </p>
<a href=""></a>
<ul>
(
Array.map(tuts, tut =>
<li key=tut> (ReasonReact.string(tut)) </li>
)
|> ReasonReact.array
)
</ul>
</div>
},
};