ReScript 真好玩-ReScript 绑定 Day.js

64 阅读3分钟

目标

来用 ReScript 绑定一下 Day.js 的来处理时间相关的操作

从简单使用开始

我们在之前一篇文章 ReScript 真好玩-ReScript 简化版 Redux 实现 的项目基础上,进一步完善内容。

首先是把 Day.js 安装好,直接 bun i dayjs 安装好依赖,接着我们看一下 Day.js 官方文档如何使用,它直接可以通过 dayjs() 创建一个对象的,所以我们先把这一步完成。
首先我们知道每个 ReScript 文件表示一个 Module,所以先上来就创建一个 Dayjs.res 文件放在 src 目录下,接着按照惯例写一个 make 函数,这里涉及一个知识点,@module("") 这种装饰器风格的语法是表达使用某个模块,这里咱们使用 dayjs 模块

@module("dayjs") external make: unit => ? = "default"

现在我们面临一个问题,我们不知道 make 调用后是一个什么类型,而实际上这个类型又是从 JavaScript 那边来的,其实我们不用管它是什么类型,真正到我们用这个类型也只是后续给 JavaScript 那侧操作,所以我们只需要按照惯例在 Module 文件第一行标识一下

type t

@module("dayjs") external make: unit => t = "default"

这其实属于 ReScript 抽象的一部分,它提供一个类型标识,后续要表达一个 Dayjs 对象的类型只需要 Dayjs.t 就可以。
现在可以使用一下,切到之前项目的 App.res 文件,然后写上一句下面这个,就可以在控制台看到一条 Dayjs 对象的日志

// ...

@react.component
let make = () => {
  // ...
  Console.log(Dayjs.make())

  <>
    // ...
  </>
}

绑定时间格式化操作

我们接着来绑定一下 format 操作,我们可以用它把 Dayjs 的对象转成一个好理解的时间字符串,我们在 Dayjs.res 文件中写写下面这句代码,这里涉及到两个知识点,一个是 @send 语法,另一个是 (t, ~formatter: string=?) => string 中的 ~formatter,先不解释

@send external format: (t, ~formatter: string=?) => string = "format"

我们赶紧来调用一下

// ...

@react.component
let make = () => {
  // ...
  Console.log(Dayjs.make()->Dayjs.format)

  <>
    // ...
  </>
}

调用结果是一个这种风格的字符串 2024-10-23T23:00:00+08:00,我们发觉没传第二个参数,因为 ~formatter 这种语法表示这是一个可选参数,然后我们再来看看实际生成的 JavaScript 代码(这里是 App.bs.js),其他的不管,主要是发觉生成的 JavaScript 代码里有

import Dayjs from "dayjs";

// ...
console.log(Dayjs().format());
// ...

这下子就理解了 @send 的作用,它是调用一个对象的方法,这里是 Dayjs() 对象调用 format() 方法。接着再来试验一下带 formatter 参数的效果,这里我们直接结合 setInterval 函数把实时时间显示在之前的 App.res 页面上,能看到时分秒一直在页面上更新

@module("./assets/react.svg") external reactLogo: string = "default"
@module("/vite.svg") external viteLogo: string = "default"
%%raw("import './assets/css/App.css'")

open Redux

@react.component
let make = () => {
  let str = useSelector(state => state.str)
  let dispatch = useDispatch()

  let (date, setDate) = React.useState(() => "")
  setInterval(() => setDate(_ => Dayjs.make()->Dayjs.format(~formatter="HH:mm:ss")), 1000)->ignore

  <>
    <div>
      <a href="https://vitejs.dev" target="_blank">
        <img src={viteLogo} className="logo" alt="Vite logo" />
      </a>
      <a href="https://react.dev" target="_blank">
        <img src={reactLogo} className="logo react" alt="React logo" />
      </a>
    </div>
    <h1> {`Vite + React + ${str} + ${date}`->React.string} </h1>
    <div className="card">
      <button onClick={_ => dispatch(Add("ReScript"))}> {`ReScript`->React.string} </button>
      <p>
        {"Edit "->React.string}
        <code> {"src/App.res"->React.string} </code>
        {" and save to test HMR"->React.string}
      </p>
    </div>
    <p className="read-the-docs">
      {"Click on the Vite and React logos to learn more"->React.string}
    </p>
  </>
}

其他 API 的绑定

有了上面的基础,其他还能绑定其他的 Dayjs API,不过篇幅有限,知晓怎么绑定,后续可以在实际开发中进行。这里再给出几个绑定,譬如我们可以用 Dayjs 来比较两个时间,或者把一段正确的时间字符串时间转成 Dayjs 对象

// Dayjs.make()->Dayjs.isAfter("2024-11-01"->Dayjs.parseString)
@send external isAfter: (t, t) => bool = "isAfter"
@module("dayjs") external parseString: string => t = "default"