从 React 到 Reason
如果你是一个 React 爱好者,开始在各种站点听到有人谈论 Reason 这个新语言,也看见 Jordan(React 作者)说 ReasonReact 将是未来,但你却是不知道从哪下手,那么这篇小教程就是为你准备的。 ps. 有条件的话还是尽量看 Reason 和 ReasonReact 的官方文档吧 pps. Jared 写的 A ReasonReact Tutorial 是 ReasonReact 最棒的入门指南。本文也是经由他允许,参考了很多其中的内容。能看的懂英语的都直接去他那里吧~ Reason 是什么?Reason 是一门基于 OCaml 的语言,它为 Ocaml 带来了新的语法和工具链。它既可以通过 BuckleScript 被同编译为 JavaScript,也支持直接编译为原生的二进制汇编。Reason 提供了和 JavaScript 相似的语法,也可以使用 npm 来安装依赖。长江后浪推前浪,Reason 丢掉了历史包袱,比 JavaScript 多了可靠的静态类型,也更快更简洁! 为什么要学 Reason ?“为啥我要花时间学一门全新的语言呢?是 JavaScript 哪里不好还是你们要求太高?” 错!Reason 不是一门全新的语言,事实上 80% 的语义都可以直接对应到现代的 JavaScript 上,反之也差不多。你只需要丢弃掉一丢丢的 JavaScript 边角语法,再学一点点好东西,就可以获得也许 ES2030 才有的特性。对于大部分人来说,学习 Reason 也不会比学习 JavaScript 和一个其他的类型系统(比如 Flow)来的慢。 不相信的话,先自己去看看 JS -> Reason 速查表,然后去 playground 体验一下吧。 从哪开始?如果你体验了一下,还是提不起兴趣,你可以再出门右转逛逛隔壁家 elm 和 ClojureScript 试试。但如果你觉得 ok,却不知道从哪下手,那不妨和我一样,从咱们熟悉的 React 开始。Jordan 重新发起了 ReasonReact 这个新项目,让我们可以换一种更简单优雅的方式写 React。 ReasonReactReasonReact 提供了一些和 React 脚手架类似的工具,比如 reason-scripts。不过为了理解的深入一点,不妨从零开始搭起我们的第一个 ReasonReact 项目。新建一个项目目录,名字随意,让我们开始吧~ 当然,你也可以直接 clone 已经准备好了的 simple-reason-react-demo 项目来参考。 首先,初始化 { "name": "simple-reason-react-demo","version": "0.1.0","scripts": { "start": "bsb -make-world -w","build": "webpack -w" },"dependencies": { "react": "^16.2.0","react-dom": "^16.2.0","reason-react": "^0.3.0" },"devDependencies": { "bs-platform": "^2.1.0","webpack": "^3.10.0" } } 然后安装一下依赖: npm install --registry=https://registry.npm.taobao.org 项目里安装了最新的 React 和 ReactDOM,以及额外的 ReasonReact。而编译工具使用了前端业界标准 Webpack 和 张宏波 开发的 bs-platform。你可能暂时还弄不清 BuckleScript 在这里将要扮演怎样的角色,不过没关系,暂时你只要把他理解成 Reason -> JavaScript 的编译器就好了,就像 Babel 把 ES2016 编译成了 ES5 一样。 然后,我们添加一个 BuckleScript 的配置文件 { "name" : "simple-reason-react-demo","reason" : {"react-jsx" : 2},"refmt": 3,"bs-dependencies": ["reason-react"],"sources": "src" } 可以大概猜出来,项目用到了 reason 的 . ├── bsconfig.json ├── src ├── node_modules └── package.json 你好,ReasonReact是不是很容易的就到这里了,让我们正式开始写 Reason 吧!在 src 里新建 ReactDOMRe.renderToElementWithId( <div>(ReasonReact.stringToElement("Hello ReasonReact"))</div>,"root" ); 几乎和 React 代码一样不是么?然后我们运行编译命令 # 相当于之前写好的 'bsb -make-world -w' npm start 一切正常的话,可以看到编译成功的提示,否则就要辛苦你按错误提示排查一下了,注意 bsb 的输出对我们的很重要,一些错误提示和类型检查的信息都要通过它来看。因为我们开启了 lib ├── bs └── js └── src └── Main.js 目前我们要关注一下的是 创建 <!doctype html> <meta charset=utf8> <title>你好</title> <body> <div id="root"></div> <script src="./bundle.js"></script> 以及 const path = require('path'); module.exports = { entry: './lib/js/src/Main.js',output: { path: path.join(__dirname,"public"),filename: 'bundle.js',},}; Webpacck 配置里入口是 bsb 编译生成的 './lib/js/src/Main.js'。再打开一个终端运行 第一个组件
让我们开始第一个组件的开发,一个只能加加减减的步进器。新建一个组件文件: let component = ReasonReact.statelessComponent("Stepper"); let make = (children) => ({ ...component,render: (self) => <div> <div>(ReasonReact.stringToElement("I'm a Stepper! "))</div> </div> });
ReactDOMRe.renderToElementWithId(<Stepper />,"root"); 刷新下浏览器,你应该可以看到刚写好的组件就这么成功的 render 出来了。 你可能很好奇为什么这里没有写 熟悉 ReactJS 的同学都应该知道,jsx 并不是什么特殊的语法,只是会被编译成普通的函数调用,比如 <div>Hello React</div> // to React.createElement( "div",null,"Hello React" ); 而在 ReasonReact 中,jsx 会被翻译成 <Stepper /> /* to */ Stepper.make([||]) /* [|1,2,3|] 是 Reason 中数组的语法 */ 意思是调用 Stepper 模块的 make 函数,参数是一个空的数组。这就和我们之前写好的 let component = ReasonReact.statelessComponent("Stepper"); let make = (children) => ({ ...component,render: (self) => <div> <div>(ReasonReact.stringToElement("I'm a Stepper! "))</div> </div> }); 不同于 ReactJS 中组件的 加上 state思来想去,我们的步进器还需要一个状态,就是要显示的数字。在 Reason 中,我们需要先定义 type state = { value: int }; 如果你写过 flow 或者 typescript,一定不会觉得奇怪,这标识我们的 state 中包含 type state = { value: int }; let component = ReasonReact.reducerComponent("Stepper"); let make = (children) => ({ ...component,initialState: () => { value: 0 },reducer: ((),state) => ReasonReact.NoUpdate,render: (self) => <div> <div>(ReasonReact.stringToElement(string_of_int(self.state.value)))</div> </div> }); 聪明的你肯定一下就看懂了 在 ReactJS 中,我们依靠 type state = { value: int }; /* here */ type action = | Increase | Decrease; let component = ReasonReact.reducerComponent("Stepper"); let make = (children) => ({ ...component,reducer: (action,state) => { /* here */ switch action { | Decrease => ReasonReact.Update({value: state.value - 1}) | Increase => ReasonReact.Update({value: state.value + 1}) }; },render: (self) => <div> /* and here */ <button onClick={self.reduce((evt) => Decrease)}>(ReasonReact.stringToElement("-"))</button> <div>(ReasonReact.stringToElement(string_of_int(self.state.value)))</div> <button onClick={self.reduce((evt) => Increase)}>(ReasonReact.stringToElement("+"))</button> </div> }); 首先,我们定义了 然后我们就可以给
如果你熟悉 Redux 的话,应该非常熟悉这一套范式了(虽然这其实来源于 Elm)。不同的是,我们直接拥有不可变的数据,不再需要过度的使用 JavaScript 的 继续?这篇文章到这里也就暂时结束了,距离能做出一般的组件功能我们还差了很多东西。目前我也只是在一些个人的小项目中使用 Reason,文章内容很浅,主要是希望能启发下厉害的你去尝试 Reason 这个还算新鲜的语言,相信它会让你眼前一亮的。 对了,既然都看到这里了,不如再去看看今年两次 React Conf 上 chenglou 关于 Reason 的精彩演讲吧~
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |