极速开发 React — Reason 2

作者: zidea | 来源:发表于2019-03-15 07:41 被阅读63次
    Speed_Racer_promotional_image.jpg

    现在是速度至上的时代,我们必须以一敌百。才能立于不败之地。

    FCJG300-0043.jpg
    面对越来越复杂的业务逻辑,我们只能全速向前冲,这一切都需要有技术作为保障。所以我们需要选择一个能够实现快速开发的技术。
    th.jpg
    reason react 网址
    个人选择并且推荐使用 reason 来开发
    极速开发 React — Reason 1
    • 更安全,更简洁的方式去构建 React 组件
    • 完全兼容 JSX
    • 类型安全兼容 javascript 编写的组件
    • 用于一种全新的表述型 API 来描述状态管理
    rr_001.JPG

    搭建项目

    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 写了一个服务,返回值为


    rr_002.JPG
    • 我们先定义一个数据结构,用 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>
        },
    };
    

    相关文章

      网友评论

        本文标题:极速开发 React — Reason 2

        本文链接:https://www.haomeiwen.com/subject/ztycmqtx.html