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 Binding? #137

Open
SebastianStehle opened this issue Sep 19, 2023 · 3 comments
Open

Redux Binding? #137

SebastianStehle opened this issue Sep 19, 2023 · 3 comments

Comments

@SebastianStehle
Copy link

Hi,

I really like your project. I have created a binding for redux and ideally I would like to integrate it to an existing platform. Either the yjs organization or your service.

My project URL: https://github.com/SebastianStehle/yjs-redux. Your review and feedback is very welcome.

I actually created the project for https://github.com/mydraft-cc/ui and I think I will use y-sweet to add collaboration.

@paulgb
Copy link
Member

paulgb commented Sep 19, 2023

Thanks for sharing @SebastianStehle, this looks cool! And the timing is great, we've been thinking a lot lately about interfaces between Yjs and frontend UI/state libraries.

My Redux knowledge is a bit dated now, do you have an example of what some application-side code in a reducer would look like?

I'd love to help you get it set up with y-sweet, let me know if there's anything I can help with.

@SebastianStehle
Copy link
Author

My Redux knowledge is a bit dated now, do you have an example of what some application-side code in a reducer would look like?

Usually the reduxer is just a function like (state, action) => state. So it returns a new state based on the old state. There are several ways to do that:

  1. Use a library like immer.js, which creates a new state based on mutation updates. This is the recommended way by the redux toolkit: https://redux-toolkit.js.org/tutorials/quick-start
  2. Use normal javascript methods like spread operators to create a new state, which can be annoying for deep states.
  3. Use a class based approach like in my sample.

The class based approach is more exotic, but it was needed for my case.

Because yjs is not immutable, we cannot use the types directly. Therefore the redux library is responsible to update abstract types from the diff of the current and the previous state and to create a new state from the old state and the events. It is a little bit more complicated, but this is described in the readme.

The API surface is very small. It basically looks like this:

// Call this for every slice you want to synchronize.
const binder = createYjsReduxBinder(options);

binder.connectSlice(doc);

export const store = configureStore({
    reducer: binder.enhanceReducer(combineReducers({
        ... YOUR REDUCERS
    })),
    middleware: [binder.middleware()]
});

You create the binder, that registers a middleware and a reducer to the store. The reducer is needed to accept the incoming changes (because there is no API for something like store.setState()) and the middleware is responsible to listen to changes. They exist through the lifetime of the application.

Then connectSlice creates the connection to the doc and returns a function to destroy the connection. This is needed if you create something like mydraft and you get a new document, when you click a button.

@websiddu
Copy link

I have tested y-sweet with mobx and https://syncedstore.org and works perfectly well. Not sure about the yjs-redux tho.

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

No branches or pull requests

3 participants