極速開發 React — Reason 2

現在是速度至上的時代,我們必須以一敵百。才能立於不敗之地。


面對越來越複雜的業務邏輯,我們只能全速向前衝,這一切都需要有技術作爲保障。所以我們需要選擇一個能夠實現快速開發的技術。

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 給我們提供兩種創建組件模板
  1. statelessComponent
  2. 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>
    },
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章