Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial docs for React module #605

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"homepage": "https://reasonml.github.io/reason-react/",
"devDependencies": {
"bs-platform": "^7.3.1",
"bsdoc": "^6.0.2-alpha",
"jest": "^26.0.1",
"react": "^16.8.1",
"react-dom": "^16.8.1",
Expand Down
111 changes: 103 additions & 8 deletions src/React.re
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
[@text "React bindings for ReasonML"];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between this and /** React bindings for ReasonML */;?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to a bug in Reason 3.6 (which Jordan fixed recently), floating doc comments /** */ i.e. ones which are not attached to any structure item, are incorrectly printed as [@doc "..."] instead of the correct attribute which is [@text "..."]. So we need to directly use [@text "..."] for these.


[@text "{1 Elements}"];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make it more obvious what this does? I'd prefer something like [@docs.text "foo"];. Not a blocker but it confused me and wanted to point it out.

The @ over % is so that this doesn't need to exist at compile time, right?

Copy link
Contributor Author

@yawaramin yawaramin Aug 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would [@docs.text "foo"] work? I always assumed that without a namespace the default one would be [@ocaml.text], which is what it's short for.

The @ is required I believe because that's what OCamldoc/odoc require.


/** A React element; the equivalent of elements that get created in
JavaScript with [React.createElement]. */
Comment on lines +5 to +6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excited to get these in editors as well.

type element;

/** Use this (instead of e.g. [<span />]) to tell React not to render
anything. */
[@bs.val] external null: element = "null";

/** [float(value)] casts the float [value] into a React element. */
external float: float => element = "%identity";

/** [int(value)] casts the int [value] into a React element. */
external int: int => element = "%identity";

/** [string(value)] casts the string [value] into a React element. */
external string: string => element = "%identity";

/** [array(value)] casts the element array [value] into a React element. */
external array: array(element) => element = "%identity";

[@text "{1 Components}"];

type componentLike('props, 'return) = 'props => 'return;

/** A React component--a function that takes props and returns a React
element. */
type component('props) = componentLike('props, element);

/* this function exists to prepare for making `component` abstract */
Expand Down Expand Up @@ -39,6 +57,8 @@ external jsxs: (component('props), 'props) => element = "jsxs";
[@bs.module "react"] [@deprecated "Please use JSX syntax directly."]
external jsxsKeyed: (component('props), 'props, string) => element = "jsxs";

[@text "{1 Refs}"];

type ref('value) = {mutable current: 'value};

module Ref = {
Expand All @@ -55,6 +75,13 @@ module Ref = {
[@bs.module "react"]
external createRef: unit => ref(Js.nullable('a)) = "createRef";

[@bs.module "react"]
external forwardRef:
([@bs.uncurry] (('props, Js.Nullable.t(ref('a))) => element)) =>
component('props) =
"forwardRef";

/** Operations for working with React element children. */
module Children = {
[@bs.module "react"] [@bs.scope "Children"] [@bs.val]
external map: (element, element => element) => element = "map";
Expand All @@ -76,6 +103,8 @@ module Children = {
external toArray: element => array(element) = "toArray";
};

[@text "{1 Context}"];

module Context = {
type t('props);

Expand All @@ -93,11 +122,7 @@ module Context = {
[@bs.module "react"]
external createContext: 'a => Context.t('a) = "createContext";

[@bs.module "react"]
external forwardRef:
([@bs.uncurry] (('props, Js.Nullable.t(ref('a))) => element)) =>
component('props) =
"forwardRef";
[@text "{1 Memo}"];

[@bs.module "react"]
external memo: component('props) => component('props) = "memo";
Expand Down Expand Up @@ -143,7 +168,7 @@ module Suspense = {
"Suspense";
};

/* Experimental React.SuspenseList */
/** Experimental React.SuspenseList */
module SuspenseList = {
type revealOrder;
type tail;
Expand Down Expand Up @@ -172,19 +197,42 @@ module SuspenseList = {
}) =
"SuspenseList";
};
/* HOOKS */

[@text "{1 Hooks}"];

[@text "{2 State}"];

/*
* Yeah, we know this api isn't great. tl;dr: useReducer instead.
* It's because useState can take functions or non-function values and treats
* them differently. Lazy initializer + callback which returns state is the
* only way to safely have any type of state and be able to update it correctly.
*/

/** [useState(fn)] is the [useState] hook; it returns a pair of the
current state, and a state setter function.

[fn] must be a nullary function that returns the initial state, like
[() => 0].

The state setter function (let's call it [setState]) takes a function
(let's call it [update]) as its argument; [update] gets called by
React with the current state, and returns the new state. E.g.:

{[let (count, setCount) = React.useState(() => 0);
setCount(count => count + 1);]}
*/
[@bs.module "react"]
external useState:
([@bs.uncurry] (unit => 'state)) => ('state, ('state => 'state) => unit) =
"useState";

/** [useReducer(reducer, initialState)] is the [useReducer] hook; it
returns a pair of the current state, and an dispatch function.

[reducer(currentState, action)] is the new state.

[initialState] is the state the reducer starts with. */
[@bs.module "react"]
external useReducer:
([@bs.uncurry] (('state, 'action) => 'state), 'state) =>
Expand All @@ -201,18 +249,37 @@ external useReducerWithMapState:
('state, 'action => unit) =
"useReducer";

[@text {|{2 Effect}

The effect hooks take an argument [fn]. [fn()] runs the effect when
called by the React runtime. It also optionally returns a cancellation
function which is called if the component is unmounted.|}];

/** [useEffect(fn)] runs the effect [fn] on every render. */
[@bs.module "react"]
external useEffect: ([@bs.uncurry] (unit => option(unit => unit))) => unit =
"useEffect";

/** [useEffect0(fn)] runs the effect [fn] on first render only. */
[@bs.module "react"]
external useEffect0:
([@bs.uncurry] (unit => option(unit => unit)), [@bs.as {json|[]|json}] _) =>
unit =
"useEffect";

/** [useEffect1(fn, deps)] runs the effect [fn] when any of the values in
the [deps] array changes. [deps] is meant to be used to pass in a
single value, but can be used to pass in any number of values (as
long as they are of the same type). */
[@bs.module "react"]
external useEffect1:
([@bs.uncurry] (unit => option(unit => unit)), array('a)) => unit =
"useEffect";

[@text {|The rest of the [useEffect] hooks take different-arity tuples as
their dependencies arguments, to model exact numbers of effect
dependencies.|}];

[@bs.module "react"]
external useEffect2:
([@bs.uncurry] (unit => option(unit => unit)), ('a, 'b)) => unit =
Expand Down Expand Up @@ -244,6 +311,9 @@ external useEffect7:
unit =
"useEffect";

[@text {|The following [useLayoutEffect] bindings are modelled similarly
to the [useEffect] bindings.|}];

[@bs.module "react"]
external useLayoutEffect:
([@bs.uncurry] (unit => option(unit => unit))) => unit =
Expand Down Expand Up @@ -288,6 +358,8 @@ external useLayoutEffect7:
unit =
"useLayoutEffect";

[@text "{2 Memo}"];

[@bs.module "react"]
external useMemo: ([@bs.uncurry] (unit => 'any)) => 'any = "useMemo";
[@bs.module "react"]
Expand Down Expand Up @@ -319,9 +391,16 @@ external useMemo7:
([@bs.uncurry] (unit => 'any), ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'any =
"useMemo";

/* This is used as return values */
[@text "{2 Callback}"];

/** This type forces BuckleScript to treat the hook return value as a
function. */
type callback('input, 'output) = 'input => 'output;

/* TODO: should we even bother to bind the first two? The whole point of
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rickyvetter (and/or others): does it make sense to use useCallback and useMemo hooks without dependencies?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ummm. Yeah should probably remove these. Good callout.

useCallback is memoizing the callback based on its dependencies; and
the dependencies need to correct too. */

[@bs.module "react"]
external useCallback:
([@bs.uncurry] ('input => 'output)) => callback('input, 'output) =
Expand Down Expand Up @@ -365,11 +444,17 @@ external useCallback7:
callback('input, 'output) =
"useCallback";

[@text "{2 Context}"];

[@bs.module "react"]
external useContext: Context.t('any) => 'any = "useContext";

[@text "{2 Ref}"];

[@bs.module "react"] external useRef: 'value => ref('value) = "useRef";

[@text "{2 Imperative Handle}"];

[@bs.module "react"]
external useImperativeHandle0:
(
Expand Down Expand Up @@ -442,6 +527,9 @@ external useImperativeHandle7:
unit =
"useImperativeHandle";

/** Uncurried versions of the hooks bindings. Use these if you want to
handle currying/not currying explicitly instead of letting
BuckleScript do it. */
module Uncurried = {
[@bs.module "react"]
external useState:
Expand Down Expand Up @@ -513,6 +601,8 @@ module Uncurried = {
"useCallback";
};

[@text "{2 Transition}"];

type transitionConfig = {timeoutMs: int};

[@bs.module "react"]
Expand All @@ -521,8 +611,13 @@ external useTransition:
(callback(callback(unit, unit), unit), bool) =
"useTransition";

[@text "{1 Display Name}"];

/** [setDisplayName(component, name)] sets the React [component]'s
display name. */
[@bs.set]
external setDisplayName: (component('props), string) => unit = "displayName";

/** [displayName(component)] is the [component]'s display name or [None]. */
[@bs.get] [@bs.return nullable]
external displayName: component('props) => option(string) = "displayName";
14 changes: 6 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# yarn lockfile v1


<<<<<<< HEAD
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
Expand Down Expand Up @@ -817,11 +816,16 @@ browser-process-hrtime@^1.0.0:
resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626"
integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==

bs-platform@^7.3.0:
bs-platform@^7.3.1:
version "7.3.2"
resolved "https://registry.yarnpkg.com/bs-platform/-/bs-platform-7.3.2.tgz#301f5c9b4e8cf5713cb60ca22e145e56e793affe"
integrity sha512-seJL5g4anK9la4erv+B2o2sMHQCxDF6OCRl9en3hbaUos/S3JsusQ0sPp4ORsbx5eXfHLYBwPljwKXlgpXtsgQ==

bsdoc@^6.0.2-alpha:
version "6.0.2-alpha"
resolved "https://registry.yarnpkg.com/bsdoc/-/bsdoc-6.0.2-alpha.tgz#77956e2f29c62592e275a6704667dab000b07da3"
integrity sha512-Zr3Z4U+lynz6FK9vqz+45jTBlKgWJ6iUssQcAU+2QUGtGMg0TNEJz2QEOvwkz5ZFVv+gLbF+c8sbhkYO4OjLJg==

[email protected]:
version "2.1.1"
resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"
Expand Down Expand Up @@ -3568,9 +3572,3 @@ yargs@^15.3.1:
which-module "^2.0.0"
y18n "^4.0.0"
yargs-parser "^18.1.1"
=======
[email protected]:
version "7.3.1"
resolved "https://registry.yarnpkg.com/bs-platform/-/bs-platform-7.3.1.tgz#2c148fb8aef687c6c195eae5821b31e887fb5bc4"
integrity sha512-RlQexm6i2gMKsfuHL8IcOHN0R/SQgxiurP96fo2nj71QgQQRh332ahOwIl0p0yNl9DH2Tg7ZV2pjG6MMMkaU6w==
>>>>>>> 5bdd3f042058ed5be0b806ce375c5e28a74865bd