现在是速度至上的时代,我们必须以一敌百。才能立于不败之地。
面对越来越复杂的业务逻辑,我们只能全速向前冲,这一切都需要有技术作为保障。所以我们需要选择一个能够实现快速开发的技术。
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>
},
};