Skip to content

Commit

Permalink
rescript react
Browse files Browse the repository at this point in the history
  • Loading branch information
Samuel Nichols authored and Samuel Nichols committed May 7, 2021
1 parent fa3098e commit 05967cd
Show file tree
Hide file tree
Showing 11 changed files with 65 additions and 65 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ and add it to `bsconfig.json`:

## Hooks

`ReasonReact` version 0.7.0 has added [support](https://reasonml.github.io/reason-react/blog/2019/04/10/react-hooks) for react hooks and `reductive` now includes a set of hooks to subscribe to the store and dispatch actions. With the new hooks there is no need to use `Lense`s that wrap components, which results in simpler and cleaner code with a flat component tree. Moreover, the new hooks API is [safe to use in concurrent mode](https://github.com/facebook/react/tree/master/packages/use-subscription#use-subscription).
`React` version 0.7.0 has added [support](https://reasonml.github.io/reason-react/blog/2019/04/10/react-hooks) for react hooks and `reductive` now includes a set of hooks to subscribe to the store and dispatch actions. With the new hooks there is no need to use `Lense`s that wrap components, which results in simpler and cleaner code with a flat component tree. Moreover, the new hooks API is [safe to use in concurrent mode](https://github.com/facebook/react/tree/master/packages/use-subscription#use-subscription).

The `Lense` API is still available, since there is support for the old `jsx` and reducer style components, but is marked as deprecated, since the old `jsx` syntax is also [deprecated](https://reasonml.github.io/reason-react/docs/en/jsx-2) in the `reason-react` docs. The preferred way of using `reductive` is via the new hooks API.

### Requirements

The new hooks API is built on top of the existing `react` hooks. In order to use hooks in `ReasonReact`, you have to use the [new jsx](https://reasonml.github.io/reason-react/blog/2019/04/10/react-hooks) syntax for `ReasonReact` components and `^5.0.4` or `^6.0.1` of `bs-platform`.
The new hooks API is built on top of the existing `react` hooks. In order to use hooks in `React`, you have to use the [new jsx](https://reasonml.github.io/reason-react/blog/2019/04/10/react-hooks) syntax for `React` components and `^5.0.4` or `^6.0.1` of `bs-platform`.

New projects will use the latest `jsx` version by default at the [application level](https://reasonml.github.io/reason-react/docs/en/jsx#application-level) by having `"react-jsx": 3` in `bsconfig.json`. Existing projects can be gradually converted using `[@bs.config {jsx: 3}]` to enable the new version at the [file level](https://reasonml.github.io/reason-react/docs/en/jsx#file-level).

Expand Down Expand Up @@ -78,7 +78,7 @@ This will create a "typed" version of the store context and hooks with the `acti
Finally, use the provider from `AppStore` when rendering your root component passing in the created `store`:

```reason
ReactDOMRe.renderToElementWithId(
ReactDOM.renderToElementWithId(
<AppStore.Provider store=appStore> <Root /> </AppStore.Provider>,
"root",
);
Expand Down
2 changes: 1 addition & 1 deletion examples/immutable/immutableEntry.res
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@@bs.config({jsx: 3})
ReactDOMRe.renderToElementWithId(
ReactDOM.renderToElementWithId(
<TimeTravelStore.Provider store=TimeTravelStore.timeTravelStore>
<ImmutableRenderer />
</TimeTravelStore.Provider>,
Expand Down
18 changes: 9 additions & 9 deletions examples/immutable/immutableRenderer.res
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,28 @@ let make = () => {
)

<div>
<div> {ReasonReact.string("string: " ++ state.notACounter)} </div>
<div> {ReasonReact.string("counter: " ++ string_of_int(state.counter))} </div>
<div> {React.string("string: " ++ state.notACounter)} </div>
<div> {React.string("counter: " ++ string_of_int(state.counter))} </div>
<button onClick={_ => dispatch(TimeTravelStore.CounterAction(SimpleStore.Increment))}>
{ReasonReact.string("Increment")}
{React.string("Increment")}
</button>
<button onClick={_ => dispatch(TimeTravelStore.CounterAction(SimpleStore.Decrement))}>
{ReasonReact.string("Decrement")}
{React.string("Decrement")}
</button>
<button onClick={_ => dispatch(TimeTravelStore.StringAction(TimeTravelStore.A))}>
{ReasonReact.string("add a")}
{React.string("add a")}
</button>
<button onClick={_ => dispatch(ReduxThunk.Thunk(incrementAsync))}>
{ReasonReact.string("Increment Async")}
{React.string("Increment Async")}
</button>
<button onClick={_ => dispatch(ReduxThunk.Thunk(incrementIfOdd))}>
{ReasonReact.string("Increment if Odd")}
{React.string("Increment if Odd")}
</button>
<button onClick={_ => dispatch(TimeTravelStore.TravelBackward)}>
{ReasonReact.string("Undo")}
{React.string("Undo")}
</button>
<button onClick={_ => dispatch(TimeTravelStore.TravelForward)}>
{ReasonReact.string("Redo")}
{React.string("Redo")}
</button>
</div>
}
14 changes: 7 additions & 7 deletions examples/react/dataRenderer.res
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,22 @@ let make = () => {
)

<div>
<div> {ReasonReact.string("string: " ++ state.notACounter)} </div>
<div> {ReasonReact.string("counter: " ++ string_of_int(state.counter))} </div>
<div> {React.string("string: " ++ state.notACounter)} </div>
<div> {React.string("counter: " ++ string_of_int(state.counter))} </div>
<button onClick={_ => dispatch(ThunkedStore.CounterAction(SimpleStore.Increment))}>
{ReasonReact.string("Increment")}
{React.string("Increment")}
</button>
<button onClick={_ => dispatch(ThunkedStore.CounterAction(SimpleStore.Decrement))}>
{ReasonReact.string("Decrement")}
{React.string("Decrement")}
</button>
<button onClick={_ => dispatch(ThunkedStore.StringAction(ThunkedStore.A))}>
{ReasonReact.string("add a")}
{React.string("add a")}
</button>
<button onClick={_ => dispatch(ReduxThunk.Thunk(incrementAsync))}>
{ReasonReact.string("Increment Async")}
{React.string("Increment Async")}
</button>
<button onClick={_ => dispatch(ReduxThunk.Thunk(incrementIfOdd))}>
{ReasonReact.string("Increment if Odd")}
{React.string("Increment if Odd")}
</button>
</div>
}
2 changes: 1 addition & 1 deletion examples/react/reactEntry.res
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@@bs.config({jsx: 3})
ReactDOMRe.renderToElementWithId(
ReactDOM.renderToElementWithId(
<ThunkedStore.Provider store=ThunkedStore.appStore> <DataRenderer /> </ThunkedStore.Provider>,
"index",
)
8 changes: 4 additions & 4 deletions examples/render-v2/renderEntryV2.res
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ module ContentComponent = {
let dispatch = Store.useDispatch()
let state = Store.useSelector(Store.Selectors.contentState)
<div>
<div> {ReasonReact.string("Content: " ++ state)} </div>
<button onClick={_ => dispatch(StringAction(AppendA))}> {ReasonReact.string("+A")} </button>
<button onClick={_ => dispatch(StringAction(AppendB))}> {ReasonReact.string("+B")} </button>
<div> {React.string("Content: " ++ state)} </div>
<button onClick={_ => dispatch(StringAction(AppendA))}> {React.string("+A")} </button>
<button onClick={_ => dispatch(StringAction(AppendB))}> {React.string("+B")} </button>
</div>
}
}
Expand All @@ -110,4 +110,4 @@ module RenderApp = {
</div>
}

ReactDOMRe.renderToElementWithId(<RenderApp />, "index")
ReactDOM.renderToElementWithId(<RenderApp />, "index")
14 changes: 7 additions & 7 deletions examples/render/renderEntry.res
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ module StringComponent = {
let state = AppStore.useSelector(contentSelector)

<div>
<div> {ReasonReact.string("Content: " ++ state)} </div>
<button onClick={_ => dispatch(StringAction(AppendA))}> {ReasonReact.string("+A")} </button>
<button onClick={_ => dispatch(StringAction(AppendB))}> {ReasonReact.string("+B")} </button>
<div> {React.string("Content: " ++ state)} </div>
<button onClick={_ => dispatch(StringAction(AppendA))}> {React.string("+A")} </button>
<button onClick={_ => dispatch(StringAction(AppendB))}> {React.string("+B")} </button>
</div>
}
}
Expand All @@ -89,12 +89,12 @@ module CounterComponent = {
let state = AppStore.useSelector(counterSelector)

<div>
<div> {ReasonReact.string("Counter: " ++ string_of_int(state))} </div>
<div> {React.string("Counter: " ++ string_of_int(state))} </div>
<button onClick={_ => dispatch(CounterAction(Increment))}>
{ReasonReact.string("++")}
{React.string("++")}
</button>
<button onClick={_ => dispatch(CounterAction(Decrement))}>
{ReasonReact.string("--")}
{React.string("--")}
</button>
</div>
}
Expand All @@ -105,4 +105,4 @@ module RenderApp = {
let make = () => <div> <CounterComponent /> <StringComponent /> </div>
}

ReactDOMRe.renderToElementWithId(<RenderApp />, "index")
ReactDOM.renderToElementWithId(<RenderApp />, "index")
28 changes: 14 additions & 14 deletions examples/todomvc/todomvcEntry.res
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
@@bs.config({jsx: 3})
@ocaml.doc("
* Example of a todo list, loosely based on the redux example, mixed with
* some code from Jared Forsyth's ReasonReact tutorial, and Cheng Lou's
* todomvc ReasonReact example.
* some code from Jared Forsyth's React tutorial, and Cheng Lou's
* todomvc React example.
*
* Borrowed CSS from https://github.com/tastejs/todomvc-app-css
")
Expand Down Expand Up @@ -115,7 +115,7 @@ module TodoItem = {
let optionRef = editFieldRef->React.Ref.current->Js.Nullable.toOption
switch (state.editing, optionRef) {
| (true, Some(field)) =>
let node = ReactDOMRe.domElementToObj(field)
let node = ReactDOM.domElementToObj(field)
Js.log(node)

ignore(node["focus"]())
Expand Down Expand Up @@ -152,11 +152,11 @@ module TodoItem = {
checked=todo.completed
onChange={_ => dispatch(ToggleItem(todo.id))}
/>
<label onDoubleClick={_ => todoItemDispatch(Edit)}> {ReasonReact.string(todo.text)} </label>
<label onDoubleClick={_ => todoItemDispatch(Edit)}> {React.string(todo.text)} </label>
<button className="destroy" onClick={_ => dispatch(ClearItem(todo.id))} />
</div>
<input
ref={ReactDOMRe.Ref.domRef(editFieldRef)}
ref={ReactDOM.Ref.domRef(editFieldRef)}
className="edit"
value=state.editText
onBlur={_ => submit()}
Expand Down Expand Up @@ -186,8 +186,8 @@ module TodoList = {
onChange={_ => dispatch(ToggleAll(activeTodoCount > 0))}
checked={todoCount > 0 && activeTodoCount === 0}
/>
<label htmlFor="toggle-all"> {ReasonReact.string("Mark all as complete")} </label>
<ul className="todo-list"> {ReasonReact.array(Belt.List.toArray(todoItems))} </ul>
<label htmlFor="toggle-all"> {React.string("Mark all as complete")} </label>
<ul className="todo-list"> {React.array(Belt.List.toArray(todoItems))} </ul>
</section>
}
}
Expand Down Expand Up @@ -239,7 +239,7 @@ module FilterLink = {
@react.component
let make = (~filter, ~label, ~state: appState, ~dispatch) => {
let className = filter == state.filter ? "selected" : ""
<li> <a className onClick={_ => dispatch(Show(filter))}> {ReasonReact.string(label)} </a> </li>
<li> <a className onClick={_ => dispatch(Show(filter))}> {React.string(label)} </a> </li>
}
}

Expand All @@ -252,13 +252,13 @@ module Footer = {
let clearButton =
completedCount > 0
? <button className="clear-completed" onClick={_ => dispatch(ClearCompleted)}>
{ReasonReact.string("Clear completed")}
{React.string("Clear completed")}
</button>
: ReasonReact.null
: React.null
<footer className="footer">
<span className="todo-count">
<strong> {ReasonReact.string(string_of_int(activeTodoCount))} </strong>
{ReasonReact.string(" " ++ (activeTodoWord ++ " left"))}
<strong> {React.string(string_of_int(activeTodoCount))} </strong>
{React.string(" " ++ (activeTodoWord ++ " left"))}
</span>
<ul className="filters">
<FilterLink filter=ALL label="All" state dispatch />
Expand All @@ -280,15 +280,15 @@ module App = {

<div>
<header className="header">
<h1> {ReasonReact.string("todos")} </h1> <AddTodo dispatch />
<h1> {React.string("todos")} </h1> <AddTodo dispatch />
</header>
<VisibleTodoList state dispatch />
<Footer state dispatch />
</div>
}
}

ReactDOMRe.renderToElementWithId(
ReactDOM.renderToElementWithId(
<AppStore.Provider store=appStore> <App /> </AppStore.Provider>,
"TodoApp",
)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"author": "rickyvetter",
"license": "MIT",
"peerDependencies": {
"reason-react": "^0.7.0"
"reason-react": "^0.9.1"
},
"devDependencies": {
"@glennsl/bs-jest": "^0.4.8",
Expand Down
20 changes: 10 additions & 10 deletions src/reductive.res
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ module Lense = {
| UpdateState
| AddListener(action => unit)
let createMake = (~name="Lense", ~lense: 'state => 'lense, store: Store.t<'action, 'state>) => {
let innerComponent = ReasonReact.reducerComponent(name)
let innerComponent = React.reducerComponent(name)
let make = (
~component: (
~state: 'lense,
~dispatch: 'action => unit,
array<ReasonReact.reactElement>,
) => ReasonReact.component<'a, 'b, 'c>,
_children: array<ReasonReact.reactElement>,
): ReasonReact.component<state<'lense>, ReasonReact.noRetainedProps, action> => {
array<React.reactElement>,
) => React.component<'a, 'b, 'c>,
_children: array<React.reactElement>,
): React.component<state<'lense>, React.noRetainedProps, action> => {
...innerComponent,
initialState: () => {
reductiveState: Some(lense(Store.getState(store))),
Expand All @@ -66,16 +66,16 @@ module Lense = {
reducer: (action, state) =>
switch action {
| AddListener(send) =>
ReasonReact.Update({
React.Update({
unsubscribe: Some(Store.subscribe(store, _ => send(UpdateState))),
reductiveState: Some(lense(Store.getState(store))),
})
| UpdateState =>
lense(Store.getState(store))
->Some
->Belt.Option.eq(state.reductiveState, (a, b) => a === b)
? ReasonReact.NoUpdate
: ReasonReact.Update({
? React.NoUpdate
: React.Update({
...state,
reductiveState: Some(lense(Store.getState(store))),
})
Expand All @@ -88,8 +88,8 @@ module Lense = {
},
render: ({state}) =>
switch state.reductiveState {
| None => ReasonReact.null
| Some(state) => ReasonReact.element(component(~state, ~dispatch=Store.dispatch(store), []))
| None => React.null
| Some(state) => React.element(component(~state, ~dispatch=Store.dispatch(store), []))
},
}
make
Expand Down
16 changes: 8 additions & 8 deletions src/reductive.resi
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ module Lense: {
~component: (
~state: 'lense,
~dispatch: 'action => unit,
array<ReasonReact.reactElement>,
) => ReasonReact.component<'a, 'b, 'c>,
array<ReasonReact.reactElement>,
) => ReasonReact.component<state<'lense>, ReasonReact.noRetainedProps, action>
array<React.reactElement>,
) => React.component<'a, 'b, 'c>,
array<React.reactElement>,
) => React.component<state<'lense>, React.noRetainedProps, action>
}

module Provider: {
Expand All @@ -46,10 +46,10 @@ module Provider: {
~component: (
~state: 'state,
~dispatch: 'action => unit,
array<ReasonReact.reactElement>,
) => ReasonReact.component<'a, 'b, 'c>,
array<ReasonReact.reactElement>,
) => ReasonReact.component<state<'state>, ReasonReact.noRetainedProps, action>
array<React.reactElement>,
) => React.component<'a, 'b, 'c>,
array<React.reactElement>,
) => React.component<state<'state>, React.noRetainedProps, action>
}

/* ** These are all visible apis of Redux that aren't needed in Reason.
Expand Down

0 comments on commit 05967cd

Please sign in to comment.