-
Notifications
You must be signed in to change notification settings - Fork 40
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
Integration with Redux devtools #30
Comments
I would LOVE that, however, we are currently limited by the Bucklescript's internal memory representation of records/variants as arrays; we don't have record keys available for serialization. Related: rescript-lang/rescript-compiler#2690 and rescript-lang/rescript-compiler#2556 |
Interesting. So, I guess this a really practical example of this being a problem, like you were describing in the interview before. FWIW, PureScript records compile to plain JS objects. I think that's the right way to go, purely for simplicity & interop reasons... |
The reasoning behind records as arrays is that Bucklescript is very performance optimized, and working with arrays has a lot of performance benefits. From what I'm aware, debug output (which should cover this use case) is an upcoming focus of the Reason core team. I am also not as concerned with lightning-speed performance than I am with great debugging experience, but given that they're working on the debugging story soon, maybe it will be the best of both worlds? |
Re: interop, there are mechanisms available for userland Records=>JS.Object: https://bucklescript.github.io/docs/en/generate-converters-accessors.html#convert-between-jst-object-and-record These require opt-in by the user, however, and aren't good for the general case such as this. |
New BuckleScript features should help with this https://bucklescript.github.io/blog/2018/05/21/release-3-1-0.html |
@joshburgess: It does help. Here is quite an experimental but working example. module ReduxDevTools {
[@bs.deriving abstract]
type serializeOptions = {
symbol: bool,
replacer: (string, Js.t({.})) => Js.t({.})
};
[@bs.deriving abstract]
type composeOptions = {
name: string,
serialize: serializeOptions
};
type extension = Js.t({.});
type connection = Js.t({.});
[@bs.module "redux-devtools-extension"]
external _devToolsEnhancer: extension = "devToolsEnhancer";
let devToolsEnhancer = _devToolsEnhancer;
[@bs.send] external _connect: (extension, composeOptions) => connection = "connect";
let connect = (instance, options) => _connect(instance, options);
[@bs.send] external _send: (connection, Js.t({.}), Js.t({.})) => unit = "send";
let send = (instance, action, state) => _send(instance, action, state);
};
type action =
| Increment
| Decrement;
let counter = (state, action) =>
switch action {
| Increment => state + 1
| Decrement => state - 1
};
type appActions = CounterAction(action, Js.Dict.t(string));
type someSubstate = {
magic: string,
someMoreMagic: string
}
type appState = {
counter: int,
substate: someSubstate
};
let appReducer = (state, action) =>
switch action {
| CounterAction(action, _) => {...state, counter: counter(state.counter, action)}
};
let sarializer: Js.t({.}) => Js.t({.}) = [%raw {|
function _serialize(obj) {
const symbols = Object.getOwnPropertySymbols(obj);
const variantNameSymbolIdx = symbols.findIndex(symbol => String(symbol) == 'Symbol(BsVariant)');
const recordSymbolIdx = symbols.findIndex(symbol => String(symbol) == 'Symbol(BsRecord)');
if(variantNameSymbolIdx > -1){
const variantName = obj[symbols[variantNameSymbolIdx]];
return {
...Object.keys(obj).reduce((target, key) => ({
...target,
['arg_'+key]: _serialize(obj[key])
}),{}),
type: variantName
}
} else if(recordSymbolIdx > -1) {
const keys = obj[symbols[recordSymbolIdx]];
return keys.reduce((object, key, index) => ({
...object,
[key]: _serialize(obj[index])
}), {})
} else {
return obj
}
}
|}];
let serializeWithRecordKeys = (_, value) => sarializer(value)
let options = ReduxDevTools.composeOptions(
~name="ReductiveTests",
~serialize=ReduxDevTools.serializeOptions(
~symbol=true,
~replacer=serializeWithRecordKeys
)
);
let connection = ReduxDevTools.connect(ReduxDevTools.devToolsEnhancer, options);
let devToolsEnhancer = (store, next, action) => {
let returnValue = next(action);
ReduxDevTools.send(connection, sarializer(Obj.magic(action)), Obj.magic(Reductive.Store.getState(store)));
returnValue
};
let store = Reductive.Store.create(
~reducer=appReducer,
~preloadedState={
counter: 0,
substate: {
magic: "...",
someMoreMagic: "well..."
}},
~enhancer=devToolsEnhancer,
()
);
ReduxDevTools.send(connection, Obj.magic("INIT"), Obj.magic(Reductive.Store.getState(store)));
let dispatch = Reductive.Store.dispatch(store);
dispatch(CounterAction(Increment, Js.Dict.fromList([("foo", "foo"), ("bar", "someTest")]))); @quicksnap: It would be great to have this kind of |
Integration with Redux devtools is now available with ambientlight/reductive-dev-tools |
now with upcoming: What's new in release 7, having records compiled into JS objects may results in cleaner representation in devtools monitor, as currently reductive-dev-tools carries I will be updating ambientlight/reductive-dev-tools to accommodate that, and will be very happy if any feedback or suggestions |
What do you all think of providing some out of box integration with the Redux devtools?
A number of js state management alternatives do this. Libraries like ngrx, react-waterfall, react-automata, an unreleased library I'm currently working on, etc.
I could help work on a PR if people are interested in this.
The text was updated successfully, but these errors were encountered: