Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Building mobile apps in React Native using Reas...
Search
Mateusz Zatorski
September 13, 2018
Technology
2
420
Building mobile apps in React Native using ReasonML
These are my slides from the LambdUp 2018 conference in Prague.
https://www.lambdup.io/
Mateusz Zatorski
September 13, 2018
Tweet
Share
More Decks by Mateusz Zatorski
See All by Mateusz Zatorski
The missing R in React
knowbody
0
41
React Router 1.0
knowbody
1
94
Other Decks in Technology
See All in Technology
Tenstorrent HW/SW 概要説明
tenstorrent_japan
0
370
Whats_new_in_Podman_and_CRI-O_2025-06
orimanabu
3
160
Roo CodeとClaude Code比較してみた
pharma_x_tech
1
260
All About Sansan – for New Global Engineers
sansan33
PRO
1
1.2k
AIエージェントのフレームワークを見るときの個人的注目ポイント
os1ma
1
500
ハッカー視点で学ぶサイバー攻撃と防御の基本
nomizone
3
1.6k
Workflows から Agents へ ~ 生成 AI アプリの成長過程とアプローチ~
belongadmin
2
110
Test Smarter, Not Harder: Achieving Confidence in Complex Distributed Systems
eliasnogueira
1
150
Kafka vs. Pulsar: Performance Evaluation by Petabyte-Scale Streaming Platform Providers
lycorptech_jp
PRO
1
350
今からでも間に合う! 生成AI「RAG」再入門 / Re-introduction to RAG in Generative AI
hideakiaoyagi
1
140
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
15
3.7k
Long journey of Continuous Delivery at Mercari
hisaharu
1
200
Featured
See All Featured
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.3k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
130
19k
For a Future-Friendly Web
brad_frost
179
9.8k
A better future with KSS
kneath
239
17k
Raft: Consensus for Rubyists
vanstee
139
7k
Being A Developer After 40
akosma
90
590k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.9k
Docker and Python
trallard
44
3.4k
Building a Modern Day E-commerce SEO Strategy
aleyda
41
7.3k
A Modern Web Designer's Workflow
chriscoyier
693
190k
Designing for humans not robots
tammielis
253
25k
Transcript
Building mobile apps in React Na4ve using ReasonML
Mateusz Zatorski Twi>er: @matzatorski GitHub: @knowbody
Story
Story Introduc4on to ReasonML
Story Introduc4on to ReasonML DEMO
Story Introduc4on to ReasonML DEMO
Why OCaml?
- func0onal - established language - compiled to: bytecode, fast
na0ve or JavaScript - full-featured type system Why OCaml?
OCaml compiler OCaml syntax OCaml seman0cs Bytecode Na0ve
js_of_ocaml OCaml syntax OCaml seman0cs Bytecode Na0ve js_of_ocaml
Bloomberg
OCaml syntax OCaml seman0cs Bytecode Na0ve Compiler backend replaced by
BuckleScript OCaml syntax OCaml seman0cs BuckleScript
Facebook
What is ReasonML?
Compiler frontend replaced by Reason Reason syntax OCaml seman0cs Bytecode
Na0ve
Combining everything together Reason syntax OCaml seman0cs BuckleScript
Where we are today? - syntax familiar to JS developers
- full power of OCaml - clean and readable JS output
Reason CLI
Reason CLI global binaries needed by editor plugins Comes with
a few extra tools: - refmt - “Reason format” - PreOer was inspired by refmt - merlin - engine powering type hint, refactor, real-0me errors, jump to defini0ons, etc. to our editors. - REPL - called rtop, interac0vely evaluates code - re:bench - online benchmarking playground - Redex - the Reason packages registry - ocamlc, ocamlopt, ocamlrun - bare ocaml compilers
Data types
Strings “Hello world” Characters ‘a’ Integers 27 -13 Floats 27.0
-13.0 Integer addi4on 27 + 13 Float addi4on 27.0 +. 13.0 Integer division/mul4plica4on 14 / 2 * 8 Float division/mul4plica4on 14.0 /. 2.0 *. 8.0 Float exponen4a4on 3.0 ** 3.0 String concatena4on “Hello ” ++ “world”
Comparison > < >= <= Boolean opera4ons ! && ||
Reference, physical (deep) equality === == Immutable lists [3, 2, 1] Arrays [|1, 2, 3|] Records type person = {age: int}; {age: 18} Comments /* my comment */
Tuple type let coordinates: (float, float) = (48.0, -120.0); let
xCoordinate = getX(coordinates); let yCoordinate = getY(coordinates);
Record type access the individual fields in a record using
the . operator: type person = { name: string, age: int, }; let matt = {name: "Mateusz", age: 12}; matt.name; /* "Mateusz" */ matt.age; /* 12 */
Variant type Variant as set of symbols (enum) type shoesColor
= | Red | Blue | Green | Black; Variant as data structure type point = | Point(float, float); type shape = | Rectangle(point, point) | Circle(point, float);
Variant type Variant as self-recursive data structure type intTree =
| Empty /* atomic */ | Node(int, intTree, intTree); /* compound */
Polymorphic type type list('a) = | Nil | Cons('a, list(‘a));
let myList = Cons("foo", Cons("bar", Cons("baz", Nil))); Singly-linked list “foo” “bar” “baz” Nil
Op0on type type option('a) = | None | Some('a); let
division = (a: int, b: int) : option(int) => if (b === 0) { None; } else { Some(a / b); }; let myLuckyNumber = division(23, 45);
Expressions
let let hardMath = { let x = 4; let
y = x - 1; x + y }; x and y are not accessible outside of hardMath scope let rec factorial = n => if (n === 0) { 1; } else { n * factorial(n - 1); };
if-else let min = (x, y) => if (x <
y) { x; } else { y; };
PaXern matching
if-else let min = (x, y) => if (x <
y) { x; } else { y; }; let min = (x, y) => switch(x < y) { | true => x | false => y };
Func0ons
Labelled arguments let add = (~x, ~y) => {/* use
x and y here */}; add(~y=5, ~x=6);
Currying let add = (x, y) => x + y;
let inc = add(1); inc(10); /* 11 */ let add = (a, b) => a + b; let alsoAdd = a => b => a + b;
Recursive func0ons let rec factorial = n => if (n
=== 0) { 1; } else { n * factorial(n - 1); };
Modules
Modules module Calc = { let add = (x, y)
=> x + y; }; Calc.add(4, 5);
JavaScript interop
JavaScript interop let jsCalculate: (array(int), int) => int = [%bs.raw
{| function (numbers, scaleFactor) { var result = 0; numbers.forEach(number => { result += number; }); return result * scaleFactor; } |} ]; let calculate = (numbers, scaleFactor) => jsCalculate(Array.of_list(numbers), scaleFactor); Js.log(calculate([1, 2, 3], 10)); /* -> 60 */
Component
Component let component = ReasonReact.statelessComponent("App"); let make = _children =>
{ ...component, render: _self => <div> <h1> (ReasonReact.string("Welcome!")) </h1> </div>, };
Component let component = ReasonReact.statelessComponent(“App"); let make = (~message, _children)
=> { ...component, render: _self => <div> (ReasonReact.string(message)) </div>, };
Component let component = ReasonReact.statelessComponent("App"); let make = (~fooProp, ~barProp,
_children) => { ...component, /* render and lifecycle methods go here */ };
Stateful component
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
Arrays
type person = { name: string, age: int, }; let
people: array(person) = [| {name: "Matt", age: 26}, {name: "Czysty", age: 6}, |]; Arrays
type person = { name: string, age: int, }; let
people: array(person) = [| {name: "Matt", age: 26}, {name: "Czysty", age: 6}, |]; let component = ReasonReact.statelessComponent("App"); let make = _children => { ...component, render: _self => <div> ( ReasonReact.array( Array.map( (person: person) => <p> (ReasonReact.string(person.name)) </p>, people, ), ) ) </div>, };
type person = { name: string, age: int, }; let
people: array(person) = [| {name: "Matt", age: 26}, {name: "Czysty", age: 6}, |]; let component = ReasonReact.statelessComponent("App"); let make = _children => { ...component, render: _self => <div> ( people |> Array.map((person: person) => <p> (ReasonReact.string(person.name)) </p> ) |> ReasonReact.array ) </div>, };
Let’s build something
Adding ReasonML to React Na0ve project yarn add bs-platform reason-react
bs-react-native
touch bsconfig.json { "name": "my-reason-react-native-app", "reason": { "react-jsx": 2 },
"bsc-flags": ["-bs-super-errors"], "bs-dependencies": ["bs-react-native", "reason-react"], "sources": [ { "dir": "src" } ], "package-specs": { "module": "commonjs", "in-source": true }, "refmt": 3 } Add bsconfig.json
Modify index.js import { app } from './src/App'; import React
from 'react'; import { AppRegistry } from 'react-native'; AppRegistry.registerComponent('MyReasonApp', () => app);
Let’s add our first component src/App.re open BsReactNative; let styles
= StyleSheet.create( Style.( { "container": style([flex(1.), justifyContent(Center), alignItems(Center)]), "text": style([fontSize(Float(26.))]), } ), ); let app = () => <View style=styles##container> <Text style=styles##text> (ReasonReact.string("Let's get this party started! " ++ {js||js})) </Text> </View>;