Margarita
Krutikova
Kyrylo
Yakymenko
a functional programming language
React bindings for ReasonML
compiles ReasonML to JavaScript
syntactic extension of
Allows writing React applications in ReasonML
"Babel" for ReasonML
Constraints
Flexibility
Guarantees
"Sweet Spot of Pragmatism"
let multiply = (a, b) => a * b;
let welcome = name => "Welcome, " ++ name;
let veggies = ["pumpkin", "kale", "broccoli"];
JavaScript developers willing to learn the OCaml syntax
type response =
| Fetching
| Error(string)
| Success(user);
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) {
...
}
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;
}
switch (action) {
| Fetching => "Fetching..."
| Error(401) => "Unauthorized!"
| Error(404) => "Not found!"
| Error(_) => "Unknown error..."
| Success(data) => data
}
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: ...";
}
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";
}
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: ..."
};
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" });
Fixed fields
Immutable
Very fast
Compile to arrays 🤯
NOTE: Not since BuckleScript 7
This simplifies interop with JS/TS code
reason-language-server
+
refmt
Start export
Started
Failed 😭
Poll for progress
Network error
1
2
3
No connection
Running
Success! 🎉
type pollingStatus =
| NotStarted
| Loading(failedRequestsCount)
| Success(apiResponse)
| NetworkError(failedRequestsCount)
| FatalError;
type action =
| PollRequest
| PollSuccess(jobStatus)
| PollError;
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(_) => ...
}
type state = {
isStarted: boolean
isLoading: boolean
failedRequests: number
isError: boolean
isFatalError: boolean
}
if (isError && !isFatalError && failedRequests < 3) {
...
...
}
😱😭
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;
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 😨
Antura
819 .ts files, 45,800 LOC
Tooling not on par with JS/TS
Sometimes tricky to find up-to-date libraries/bindings
No need to go all in from the start
React + TypeScript
Elm
WebForms
React + JavaScript
Vanilla JS/TS
ReasonReact
React + TypeScript
Official stack
React + TypeScript
React + ReasonML
Free choice when starting a new project/component
Official stack
Evaluation
WebForms
React + JavaScript
Vanilla JS/TS
Legacy
Razor/Blazor
(99% of AP)
(Gantt 2.0)
(Header, Kanban)
Companies hiring ReasonReact, Elm, etc. developers
ReasonReact 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";
};