mobxjs / mobx-state-tree

Full-featured reactive state management without the boilerplate
https://mobx-state-tree.js.org/
MIT License
6.94k stars 641 forks source link

[Question] UndoManager - Extend the Entry model and callbacks in undo/redo actions #889

Closed chemitaxis closed 6 years ago

chemitaxis commented 6 years ago

Hi as we have been talking in Twitter, I need to extend the Entry Model to add a new prop.

In my case, I have something like this:

AddUndoState:

 addUndoState(recorder) {
        if (recorder.patches.length === 0) {
          return;
        }

        if (replaying) {
          // skip recording if this state was caused by undo / redo
          return;
        }
        self.history.splice(self.undoIdx);
        self.history.push({
          zoom: $('#canva').css('transform'),
          patches: recorder.patches,
          inversePatches: recorder.inversePatches
        });

        self.undoIdx = self.history.length;
      }

I need to save the css transform in the history, because if the action was in a different "environment" (zoomed, for example), if I revert the change, I have an issue with my selector. We are not recording nothing about the zoom.

I need to extend the entry model to something like this:

const Entry = mst.types.model('UndoManagerEntry', {
  zoom: mst.types.frozen,
  patches: mst.types.frozen,
  inversePatches: mst.types.frozen
});

In the other hand, to solve my problem, I can pass a callback to the undo/redo action, and check if the "environment" is different and process in the correct way:

undo(callback) {
        replaying = true;
        self.undoIdx -= 1;
        const { zoom } = self.history[self.undoIdx];
        // n.b: reverse patches back to forth
        // TODO: add error handling when patching fails? E.g. make the operation atomic?
        mst.applyPatch(
          targetStore,
          self.history[self.undoIdx].inversePatches.slice().reverse()
        );
        replaying = false;

        callback(zoom);
      }

My callback function:

function example_callback(zoom){
          if (
            !!rootStore.canvaStore.selector &&
            zoom !== $('#canva').css('transform')
          ) {
            // DO CUSTOM STUFF HERE
          }
}

I have this working, but I have copied the code of the undoManager and I have added to my project, but I don't want to do it... any ideas? Thanks @mweststrate & @robinfehr

robinfehr commented 6 years ago

I'm still confused :) what prevents you from storing the zoom on a canvasModel/ viewModel?

mweststrate commented 6 years ago

Closing for inactivity