
Margarita
Krutikova
Kyrylo
Yakymenko
Agenda
- What is Reason?
- Why should we care?
- Language features
- The new ReasonReact hooks API
- Summary
a functional programming language
React bindings for ReasonML
compiles ReasonML to JavaScript

syntactic extension of
Allows writing React applications in ReasonML

"Babel" for ReasonML
Why?
- 
Statically typed, functional and pragmatic
 best of two worlds




Constraints
Flexibility
Guarantees




"Sweet Spot of Pragmatism"
Why?
- 
Statically typed, functional and pragmatic
 best of two worlds
- Powered by Facebook (used in production)
Why?
- 
Statically typed, functional and pragmatic
 best of two worlds
- Powered by Facebook
- Fun fact: Jordan Walke, the creator of React is now working on Reason
Why?
- 
Statically typed, functional and pragmatic
 best of two worlds
- Powered by Facebook
- Fun fact: Jordan Walke, the creator of React is now working on Reason
- Expressive type system, strong type inference
- Extremely fast builds
Why?
- 
Statically typed, functional and pragmatic
 best of two worlds
- Powered by Facebook
- Fun fact: Jordan Walke, the creator of React is now working on Reason
- Expressive type system, strong type inference
- Extremely fast builds
- Access to the whole JS ecosystem (npm)
- Incremental adoption possible
Syntax
- reminds of Javascript
    let multiply = (a, b) => a * b;
    let welcome = name => "Welcome, " ++ name;
        
    let veggies = ["pumpkin", "kale", "broccoli"];
All JavaScript
developers in the world
JavaScript developers willing to learn the OCaml syntax
The cool stuff
- 
	Variants + pattern matching

      type response = 
       | Fetching
       | Error(string)
       | Success(user);
Variant

      switch (response) {
       | Fetching => <Spinner />
       | Error(err) => <Error err />
       | Success(user) => <MyPages user />
      }     
     
     
                type Response = {
                  error: string | null,
                  user: User | null,
                  isLoading: boolean
                }
                if (response.loading) {
                 ...
                }
                if (response.error) {
                 ...
                }
                if (response.user) {
                  ...
                }Typescript





Pattern Matching (JS)
switch (action.type) {
  case "FETCHING":
    return "Fetching...";
    
  case "ERROR":
    if (action.errorCode === 401) {
      return "Unauthorized!";
    }
    if (action.errorCode === 404) {
      return "Not found!";
    }
    return "Unknown error...";
    
  case "SUCCESS":
    return action.data;
}Pattern Matching (Reason)
switch (action) {
  | Fetching => "Fetching..."
  | Error(401) => "Unauthorized!"
  | Error(404) => "Not found!"
  | Error(_) => "Unknown error..."
  | Success(data) => data
}Pattern Matching (routing)
if (isLoggedIn) {
  if (isLoggedInAsAdmin) {
    return "Access denied to admin content";
  } else {
    if (subRoute.length === 2 && subRoute[0] === "results") {
      const playerName = subRoute[1];
      return `Results for ${playerName}`;
    } else if (subRoute.length === 1 && subRoute[0] === "settings") {
      return "Settings";
    }
  }
} else {
  return "Log In: ...";
}Pattern Matching (routing)
if (!isLoggedIn) {
  return "Log In: ...";
}
if (isLoggedIn && !isLoggedInAsAdmin) {
  return "Access denied to admin content";
}
if (subRoute.length === 2 && subRoute[0] === "results") {
  const playerName = subRoute[1];
  return `Results for ${playerName}`;
}
if (subRoute.length === 1 && subRoute[0] === "settings") {
  return "Settings";
}Pattern Matching (routing)
switch (isLoggedIn, isLoggedInAsAdmin, subRoute) {
| (true, true, ["results", playerName]) =>
  "Results for " ++ playerName
| (true, true, ["settings"])
| (true, true, _) => "Settings"
| (true, false, _) => "Access denied to admin content"
| (false, _, _) => "Log in: ..."
};The cool stuff
- 
	Variants + pattern matching
- 
	Option

Option
type option('a) = None | Some('a)
- 
	No null / undefined 
- 
	Safe alternative to concept of nonexistent value 
let maybeInt = Some(45);
let maybeUser = Some({ name: "John" });The cool stuff
- 
	Variants + pattern matching
- 
	Option
- 
	Records

Records
- 
	Fixed fields 
- 
	Immutable 
- 
	Very fast 
- 
	Compile to arrays 🤯 
Similar to JS objects, but

NOTE: Not since BuckleScript 7
This simplifies interop with JS/TS code
The cool stuff
- 
	Variants + pattern matching
- 
	Option
- 
	Records
- 
	Module system
- 
	Built-in formater

Automatic code formatting
JS/TS: Prettier
- prettier-vscode
- prettier-eslint
- eslint-plugin-prettier
- eslint-config-prettier
- (tslint-config-prettier)
- .prettierrc
- .eslintrc
- settings.json -> prettier settings
reason-language-server
+
refmt
ReasonML


ReasonReact
- Reason bindings for React
- Allows writing React components to whole React applications in ReasonML
- Supports React hooks as of v0.7.0!
- Future of React? 🤔
WE WANT CODE!

Start export
Started
Failed 😭
Poll for progress
Network error
Earchive export job
1
2
3

No connection
Running
Success! 🎉
State
type pollingStatus = 
  | NotStarted
  | Loading(failedRequestsCount)
  | Success(apiResponse)
  | NetworkError(failedRequestsCount)
  | FatalError;type action = 
  | PollRequest 
  | PollSuccess(jobStatus)
  | PollError;State machine
let reducer = (state, action) => 
  switch (action) {
    | PollRequest => 
      switch (state) => {
        | NetworkError(failures) 
        | Loading(failures) => Loading(failures)
        | other => Loading(0)
      }
    | PollError => 
      switch (state) {
       | Loading(failures) when failures > 3 => FatalError
       | Loading(failures) => NetworkError(failures + 1)
       | other => other
     };
    | PollSuccess(_) => ...
  }
Typescript 🤔
type state = {
  isStarted: boolean
  isLoading: boolean
  failedRequests: number
  isError: boolean
  isFatalError: boolean
}
if (isError && !isFatalError && failedRequests < 3) {
  ...
  ...
}😱😭
Typescript 🤔
type state = 
  | { kind: "notStarted" }
  | { kind: "loading", failedRequests: number }  
  | { kind: "networkError", failedRequests: number }  
  | { kind: "fatalError" }
  | { kind: "success", apiResponse: jobStatus }type pollingStatus = 
  | NotStarted
  | Loading(failedRequestsCount)
  | Success(apiResponse)
  | NetworkError(failedRequestsCount)
  | FatalError;Making changes
Add "reconnect" button
type action = 
  | PollRequest 
  | PollSuccess
  | PollError
  | PollReset;Restart polling timer on state change in React
switch (pollingState) {
 | FatalError => 
    <Text value="Internet not responding" />
    <Button text="Reconnect" onClick=startTimer />
 | Loading => <Spinner />
 | NetworkError(_) => <Text value="Reconnecting..." />
}* 3 hours before code freeze 😨
Build times
Clean build < 3 mins
Incremental build ~ 1 s

Antura
819 .ts files, 45,800 LOC

Clean build ~ 20 s
Incremental build ~ 5-6 s
- Variants, powerful pattern matching
- Functional language, but pragmatic
 (has mutation, side effects)
- Expressive, proven type system with strong type inference
- Compilation speed
- Interop with other libs - use anything on npm!
- Possibility to compile to native code
- Driven by Facebook
Summary
- Hasn't reached a critical mass yet
- Still "raw"
- 
	Tooling not on par with JS/TS 
- 
	Sometimes tricky to find up-to-date libraries/bindings 
Disadvantages
Adoption Strategies
No need to go all in from the start
- Start with individual components
- Start with logic/functions
- Start with API decoders
Frontend Toolkit
React + TypeScript
Elm
WebForms
React + JavaScript
Vanilla JS/TS
ReasonReact










Frontend Toolkit
React + TypeScript


Official stack
Frontend Toolkit
React + TypeScript
React + ReasonML




Free choice when starting a new project/component

Official stack
Evaluation
Frontend Toolkit
WebForms
React + JavaScript
Vanilla JS/TS





Legacy



Razor/Blazor


(99% of AP)
(Gantt 2.0)
(Header, Kanban)
Frontend Toolkit
Elm

- Existing code is (almost) bug-free
- Existing code is easy to maintain
- No reason to rewrite in React
- 
Prerequisites for starting a new project:
	- A good reason
 (e.g. rendering performance)
- Interop with existing code
 (e.g. via react-elm-components)
 
- A good reason

Companies hiring React JavaScript TypeScript developers
Companies hiring ReasonReact, Elm, etc. developers
React JS/TS developers
ReasonReact developers
Companies hiring React JavaScript TypeScript developers
Companies hiring ReasonReact, Elm, etc. developers
module Panel = {
  [@bs.module "./Panel"] [@react.component]
  external make:
    (
      ~scrollable: bool=?,
      ~className: string=?,
      ~style: ReactDOMRe.Style.t=?,
      ~children: React.element
    ) =>
    React.element =
    "Panel";
};
module Content = {
  [@bs.module "./Content"] [@react.component]
  external make:
    (
      ~scrollable: bool=?,
      ~disableScroll: bool=?,
      ~style: ReactDOMRe.Style.t=?,
      ~className: string=?,
      ~children: React.element
    ) =>
    React.element =
    "Content";
};
ReasonReact (condensed)
By Kyrylo Yakymenko
ReasonReact (condensed)
- 522
 
   
   
  