ReasonReact-Helloworld

Install

這部分和 Reason 一樣

只是提供了一個 react theme

1
2
3
$ npm install -g bs-platform
$ bsb -init reason-react-demo -theme react
$ cd reason-react-demo && npm install && npm start

npm start 僅僅是將 .re 編譯為 .js

我們還需要使用 npm run webpack 作打包的動作

另外要再開一個 web-develop-server

所以另外也還要再開一個 npm run server

這些指令在初始化的時候就會產生

工程師都是懶惰的

所以現在要利用 concurrently 來幫我們簡化一下

concurrently

這個套件可以一行指令一次執行多個 process

使用上也很方便

1
$ npm install -g concurrently

command

1
$ concurrently -n reason,webpack,server "yarn start" "yarn webpack"  "yarn server"

package.json
需要使用 \ 跳脫字元

1
2
3
...,
"dev": "concurrently -n reason,webpack,server \"yarn start\" \"yarn webpack\" \"yarn server\"",
...
1
$ npm run dev

檔案結構

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
.
├── README.md
├── bsconfig.json
├── lib
│   └── bs
│   ├── ReactTemplate.cmi
│   ├── ReactTemplate.cmj
│   ├── ReactTemplate.cmt
│   ├── ReactTemplate.js
│   ├── ReactTemplate.mlmap
│   ├── build.ninja
│   └── src
│   ├── Component1-ReactTemplate.cmi
│   ├── Component1-ReactTemplate.cmj
│   ├── Component1-ReactTemplate.cmt
│   ├── Component1.mlast
│   ├── Component1.mlast.d
│   ├── Component2-ReactTemplate.cmi
│   ├── Component2-ReactTemplate.cmj
│   ├── Component2-ReactTemplate.cmt
│   ├── Component2.mlast
│   ├── Component2.mlast.d
│   ├── Index-ReactTemplate.cmi
│   ├── Index-ReactTemplate.cmj
│   ├── Index-ReactTemplate.cmt
│   ├── Index.mlast
│   └── Index.mlast.d
├── package-lock.json
├── package.json
├── src
│   ├── Component1.bs.js
│   ├── Component1.re
│   ├── Component2.bs.js
│   ├── Component2.re
│   ├── Index.bs.js
│   ├── Index.re
│   └── index.html
└── webpack.config.js

lib 裡面放的是 BuckleScript 的檔案

這部分之後再做研究

src 中放的是 .re 檔案 以及編譯過後的 .js 檔案

webpackconfig.js 就是 webpack 的設定檔案

他會以 index.bs.js 為進入點

所以第一次要先編譯之後產生這個檔案再跑 webpack 才不會出錯

src 中主要有四個檔案 index.html Index.re Component1.re Component2.re

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ReasonReact Examples</title>
</head>
<body>
Component 1:
<div id="index1"></div>
Component 2:
<div id="index2"></div>

<script src="Index.js"></script>
</body>
</html>

這邊有一個比較特別的地方

以前使用 create-react-app 建立出來的都只會有一個 <div id="root"></div>

會以這個為最外層的 div

其他的 Component 都在這個 div 之下做 render

這個範例一開始建立了兩個 div

各自 render Component1Component2

或許這之後會解釋這樣的實作有和優劣?

還是只是範例而已

Component1.re

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* This is the basic component. */
let component = ReasonReact.statelessComponent("Page");

/* Your familiar handleClick from ReactJS. This mandatorily takes the payload,
then the `self` record, which contains state (none here), `handle`, `reduce`
and other utilities */
let handleClick = (_event, _self) => Js.log("clicked!");

/* `make` is the function that mandatorily takes `children` (if you want to use
`JSX). `message` is a named argument, which simulates ReactJS props. Usage:

`<Page message="hello" />`

Which desugars to

`ReasonReact.element(Page.make(~message="hello", [||]))` */
let make = (~message, _children) => {
...component,
render: self =>
<div onClick=(self.handle(handleClick))>
(ReasonReact.string(message))
</div>,
};

Component1.re 很簡單

先將原始的 Compoennt assign 之後做解構

但是在綁定 Event 就比較特別的是

先寫了一個 function handleClick

divonClick 去 trigger

使用的方式是 onClick=(self.handle(handleClick))

變數部分也改用 () 而不是以前 React 使用的 {}

看到這邊其實跟之前的 React 會有一些不同

先做一些調整

src/index.html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ReasonReact Examples</title>
</head>
<body>
<div id="root"></div>

<script src="Index.js"></script>
</body>
</html>

App.re

1
2
3
4
5
6
7
8
9
10
11
12
let component = ReasonReact.statelessComponent("App");

let make = (_children) => {
...component,
render: (_) =>
<>
(ReasonReact.string("Component1:"))
<Component1 message="Hello!" />
(ReasonReact.string("Component2:"))
<Component2 greeting="Hello!" />
</>
};

Hot Reload

這時候會發現當我們更新了程式碼之後還是不會自動 Reload

還是有點麻煩

其實只要稍微調整一下 webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const outputDir = path.join(__dirname, 'build/');

const isProd = process.env.NODE_ENV === 'production';

module.exports = {
entry: './src/Index.bs.js',
mode: isProd ? 'production' : 'development',
output: {
path: outputDir,
publicPath: outputDir,
filename: 'Index.js',
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html',
})
],
devServer: {
compress: true,
contentBase: outputDir,
port: process.env.PORT || 8000,
historyApiFallback: true
}
};

這樣就完成囉!

Have fun!

文章目录
  1. 1. Install
    1. 1.1. concurrently
  2. 2. 檔案結構
    1. 2.1. Hot Reload
|