Initialization of a component using view & state

I am having a problem initializing a component that works on both a state and a view.

It’s easier to explain with a concrete example, suppose I want to encapsulate the functionality of the current collab demo in a module where the view and state are created outside of it.

The module needs to call methods on the view+state created outside (updateView etc). The outside created view needs to call the dispatchTransaction method of the module (or to be precise, a version of it that does not update the view).

I end up with a module exporting a single function:

// initialize collaboration, returns a function to be called from the view's dispatchTransaction
initCollab(view, getState) 

The problem I have is with initialization in the outside code. I need the function returned from initCollab when creating the view (to call it from dispatchTransaction), however I also need the view and state to pass them to initCollab.

I end up with something like this:

let collabDispatchTransaction;

let view = new MenuBarEditorView(document.querySelector("#editor"), {
    state: ...,
    dispatchTransaction: transaction => {
      collabDispatchTransaction(transaction); // !!!!
      // dispatch transaction to other places
      view.updateState(view.editor.state.apply(transaction));
    },
});

collabDispatchTransaction=initCollab(view, () =>  return view.editor.state);

This is quite awkward, I am relying on the view not calling collabDispatchTransaction until it has a value, I am also relying on initCollab being called before any code that may trigger the view’s dispatchTransaction.

What is the best way to handle this situation ?

Thx!

Ok I think I understand better, I need to create a plugin and use it’s view(EditorView) property

That works too, I guess, but here’s how I’d structure it:

function myInit() {
  let state = ...;
  let collabPlugin = createCollabPlugin({getState() { return state }})
  let view = new MenuBarEditorView(document.querySelector("#editor"), {
    state,
    dispatchTransaction(tr) {
      view.updateState(state = state.apply(transaction))
    }
  })
}

I.e. the state lives somewhere well-known (in this case, in the closure, but you’d probably use a class instance property in real code), the dispatchTransaction prop updates it, and the plugin is initialized with a function that accesses it.

Sorry I don’t understand how this works :frowning: how/where does the dispatchTransaction method of collabPlugin gets called ?

Err, yeah, that was a bit of a mess written too late at night. Ignore it.

Why do you need the view in your plugin? What does collabDispatchTransaction do? Does it need access to the transactions or can it just look at a new state and derive what happened from that, like the regular collab plugin?

Basically I want to encapsulate all collab including server communication and view updates. The component is initialized with a view and state (or a getState / updateView functions etc) and does everything. So collabDispatchTransaction is something like this and updating the view something like this

Or perhaps I’m thinking wrongly about the whole thing ?

I think that works. I don’t have enough insight into your approach to say anything useful, but the technique in my demo, where there’s a wrapping component that ‘owns’ the editor and manipulates its state, is sensible, yes.

Ok I think we don’t understand each other ,so I guess I’ll just drop it, the whole point was to avoid the way collab demo is now (which is fine for a demo of collab only but not for a bigger implementation), and to separate the view and state from the network stuff and the rest of it. Anyways …