reductive-dev-tools
reductive and reason-react reducer component integration with redux-devtools-extension
Installation
via npm:
npm install --save-dev reductive-dev-tools
then add reductive-dev-tools
to your "bs-dependencies" inside bsconfig.json
Caveats
- Add
-bs-g
into "bsc-flags"
of your bsconfig.json to have variant and record field names available inside extension. - Prefer variants with associated data to plain (
SomeAction(unit)
to SomeAction
) since plain varaints do no carry debug metedata with them (represented as numbers in js) - Extension will be locked (newly dispatched actions will be ignored) when you jump back in action history.
Supported DevTools Features
Usage with Reductive
Utilize provided store enhancer ReductiveDevTools.Connectors.reductiveEnhancer
let storeEnhancer =
ReductiveDevTools.(
Connectors.reductiveEnhancer(
Extension.enhancerOptions(~name="MyApp", ()),
)
);
let storeCreator = storeEnhancer @@ Reductive.Store.create;
Usage with ReactReason reducer component
-
Create devtools connection with ReductiveDevTools.Connectors.register()
.
/* in your component */
didMount: self =>
ReductiveDevTools.Connectors.register(
~connectionId,
~component=self,
~options=ReductiveDevTools.Extension.enhancerOptions(
~actionCreators=Js.Dict.fromList([
("click", (.) => `Click()),
("toogle", (.) => `Toggle(()))
]),
()),
()),
-
Wrap your reducer into componentReducerEnhancer
with passed connectionId and handle actions dispatched from the monitor (DevToolStateUpdate('state)
) to support rewind, revert, import extension features:
/* inside your component */
reducer: ReductiveDevTools.Connectors.componentReducerEnhancer(connectionId, ((action, state) => {
switch (action) {
| `Click(_) => ReasonReact.Update({...state, count: state.count + 1})
| `Toggle(_) => ReasonReact.Update({...state, show: !state.show})
/* handle the actions dispatched from the dev tools monitor */
| `DevToolStateUpdate(devToolsState) => ReasonReact.Update(devToolsState)
}
})),
},
-
Unsubscribe when needed with ReductiveDevTools.Connectors.unsubscribe(~connectionId)
Options
ReductiveDevTools.Extension.enhancerOptions(
/* the instance name to be showed on the monitor page */
~name="SomeTest",
/* action creators functions to be available in the Dispatcher. */
~actionCreators=Js.Dict.fromList([
("increment", (.) => CounterAction(Increment)),
("decrement", (.) => CounterAction(Decrement)),
("complexAppend", ((first, last) => StringAction(ComplexAppend(first, last))) |> Obj.magic)
]),
/* if more than one action is dispatched in the indicated interval, all new actions will be collected and sent at once */
~latency=500,
/* maximum allowed actions to be stored in the history tree. */
~maxAge=50,
/* actions types to be hidden / shown in the monitors (while passed to the reducers), If `actionsWhitelist` specified, `actionsBlacklist` is ignored. */
~actionsBlacklist=[|"StringAction"|],
/* actions types to be hidden / shown in the monitors (while passed to the reducers), If `actionsWhitelist` specified, `actionsBlacklist` is ignored. */
~actionsWhitelist=[|"CounterAction"|],
/* if specified as `true`, whenever there's an exception in reducers, the monitors will show the error message, and next actions will not be dispatched. */
~shouldCatchErrors=false,
/* If you want to restrict the extension, specify the features you allow. */
~features=ReductiveDevTools.Extension.enhancerFeatures(
~pause=true,
~persist=true,
~export=true,
~import=Obj.magic("custom"),
~jump=true,
~dispatch=true,
()),
())
Word Of Caution
Current implementation depends on internal bucklescript representation of debug metadata and variants in js. Changes to it in future may silently break the extension.