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

Redux Support #126

Open
ahahn95 opened this issue Aug 21, 2019 · 10 comments
Open

Redux Support #126

ahahn95 opened this issue Aug 21, 2019 · 10 comments
Labels
question Further information is requested

Comments

@ahahn95
Copy link

ahahn95 commented Aug 21, 2019

Can this library be used with redux? I assume that react-redux will not work so I was wondering how that could be done.

@matthewp matthewp added the question Further information is requested label Aug 21, 2019
@matthewp
Copy link
Owner

I'm sure it can be, but I'll let others answer this as I've personally never used Redux.

@threepointone
Copy link

You can totally use redux, but you’ll have build your own version of react-redux (a haunted-redux, if you will). I would recommend looking at the /hooks folder on the react-redux repo https://github.com/reduxjs/react-redux/tree/master/src/hooks

@askbeka
Copy link
Contributor

askbeka commented Aug 22, 2019

This is quite interesting,
It can work, there are some hooks missing in haunted.
useCallback, useLayoutEffect, maybe more.

I thought why not to just plug react-redux and see if it works, if it does then big win for haunted:)
I have setup a plunkr: https://next.plnkr.co/edit/8lukaUKTSzv6HOn5?preview

with importmap to load modules from unpkg and patch up things that do not work.
So now modules load,

react.js is reexporting haunted instead of React and also delivering some other hooks.

now it is failing to find a provider, but not sure why.

Do not forget to enable: importmap support. If you use chrome: chrome://flags/#enable-built-in-module-infra

@askbeka
Copy link
Contributor

askbeka commented Aug 22, 2019

context works now, problem was because of not specified module extensions in react-redux, or me specifying them on my side:). different modules were loading and singleton ReduxContext singletone module was loaded twice:)

Now useCallback and useLayoutEffect need to be implemented. react-redux can be repackaged for haunted or maybe made generic without referencing react.

@askbeka
Copy link
Contributor

askbeka commented Aug 22, 2019

Works now! https://next.plnkr.co/edit/8lukaUKTSzv6HOn5
Just replaced uselayoutEffect with useffect, and useCallback was already available.

Used es-module-shims, so no need to enable importmaps! Thanks @guybedford, works like a charm. Do not know how to feature detect if browser supports importmap to conditinally load esm-module-shims.

I hope It is clear now, what is missing, useeffect works in this example just fine.
But maybe someone could show when it doesn't

https://github.com/reduxjs/react-redux/blob/5e6205a2f9bb18e1f8b0163382bc29230ea7d3d3/src/hooks/useSelector.js#L16

@jdin
Copy link

jdin commented Aug 22, 2019

Here is a simple example with pure redux dependency:

import { component, html, useState, useEffect } from "haunted";
import { createStore } from "redux";

const counter = (state = 0, action) => {
  switch (action.type) {
    case "INCREASE":
      return state + 1;
    case "DECREASE":
      return state - 1;
    default:
      return state;
  }
};

const store = createStore(counter, 0);

const useSelector = selector => {
  const [data, setData] = useState(selector(store.getState()));
  useEffect(() => {
    return store.subscribe(() => {
      const d = selector(store.getState());
      setData(d);
    });
  }, [selector]);
  return data;
};

const useDispatch = () => action => store.dispatch(action);

const App = () => {
  const val = useSelector(s => s);
  const dispatch = useDispatch();
  return html`
    <p>val=${val}</p>
    <button @click=${() => dispatch({ type: "INCREASE" })}>+</button>
    <button @click=${() => dispatch({ type: "DECREASE" })}>-</button>
  `;
};
customElements.define("my-el", component(App));

Did not test it much yet though and probably can be improved ...

@matthewp
Copy link
Owner

useLayoutEffect should be coming pretty soon. Hadn't though of doing useCallback because it's not normal to use callbacks in web component code (events are used instead).

@askbeka
Copy link
Contributor

askbeka commented Aug 22, 2019

@jdin It works, for sure, it is simpler since it does not have a context. Well, simpler as long as all your store-connected (aka smart) components are build together with you application.

And each component using useDispatch is tighly coupled to the hook and the store it dispatches to:

See: https://next.plnkr.co/edit/TJt0M3OKT9iqfyy4
for example of two stores used, Notice that neither my-app nor my-counter has changed, and they could be shipped independently from application and combined in runtime;

Currently limitation is that Context resolution in haunted and react is performed by object reference;

Context1 === Context2

which is good if you have mutiple versions of the same context library, like react-redux in your application and want different behavior based on version, helpfull when migrating big application gradually.

But it can be changed to be checked by somthing like .valueOf

Context.valueOf = () => Symbol.for('some-context');

Context1.valueOf() === Context2.valueOf()

Then you have to manage context used by DOM tree, consumer will get the value from the closest context provider.

@matthewp My mistake, useCallback is already available in haunted!:)
useLayoutEffect is not, But react is also a bit differently implemented in regards to scheduling.
they say that useLayoutEffect callback has to be called just after commit before paint.

By this definition it can be performed in microtask after. But in docs they also mention that it callback is called synchronously after commit not sure what they mean there. Not sure if it matters if it synchronous or next microtask, since next scheduled microtask still blocks the eventloop

@askbeka
Copy link
Contributor

askbeka commented Aug 24, 2019

@matthewp Have made initial effort here

Better would be to create a haunted group to manage haunted related projects, if there will be any, but for will try to keep code there.

I have found a list of https://github.com/rehooks/awesome-react-hooks.

Some libraires just like redux have started publishing their hooks.
Would be nice to make a port for them to, so that they can be used easily with haunted.

If you have questions why I have copied the code over instead of reusing the react-redux.
I have made a comment about it.
And some hooks kind of hooked into how React works, with ids scheduling and redering which differs from haunted.

React is synchronous. haunted is not(updates are batched).
If the hooks and rendering is aligned with React more, we could just make symbiotic packages consuming hooks from other libraries and re-generating them replacing react references with ones from haunted. Something like Renovte can help keeping packages upto date.

What do you think?

@matthewp
Copy link
Owner

Related item come up with #130. We can revisit the scheduler if that will help with something.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants