luisherranz / deepsignal

DeepSignal 🧶 - Preact signals, but using regular JavaScript objects

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Resetting the initial state of a deepSignal

oravecz opened this issue · comments

I didn't see in the unit tests or the documentation an example on how one might set the entire state object.

I assume if I can extract the values using RevertDeepSignal, there might be a mechanism to set the values?

Take the following example. I assume that closeWorkbook2() will work as expected, but is there a simpler approach that works more like closeWorkbook1?

enum WorkbookLoadingState {
  Initial,
  Loading,
  Success,
  Error,
}

interface WorkbookState {
  loadingState: WorkbookLoadingState;
  attributes: Attribute[];
  categories: Category[];
  hierarchies: Hierarchy[];
  hierarchy: Hierarchy | null;
  hierarchyNodes: HierarchyNode[];
  lrsSegments: Segment[];
  segments: Segment[];
  trees: ExplicitDataSource<PlanningTreeData> | null;
  workbook: Workbook | null;
}

interface WorkbookActions {
  loadWorkbook: (workbookId: string) => void;
  closeWorkbook: () => void;
  setHierarchy: (hierarchy: Hierarchy) => void;
}

type WorkbookStore = WorkbookActions & {
  state: DeepSignal<WorkbookState>;
};

const initialState:WorkbookState = {
  attributes: [],
  categories: [],
  hierarchy: null,
  hierarchyNodes: [],
  hierarchies: [],
  loadingState: WorkbookLoadingState.Initial,
  lrsSegments: [],
  segments: [],
  trees: null,
  workbook: null,
};

// Not typesafe
const closeWorkbook1 = () => {
    store.state = initialState;
}

const closeWorkbook2 = () => {
  batch(() => {
    store.state.attributes = [];
    store.state.categories = [];
    store.state.hierarchy = null;
    store.state.hierarchyNodes = [];
    store.state.hierarchies = [];
    store.state.loadingState = WorkbookLoadingState.Initial;
    store.state.lrsSegments = [];
    store.state.segments = [];
    store.state.trees = null;
    store.state.workbook = null;
  });
}

const store: WorkbookStore = {
  state: deepSignal<WorkbookState>(initialState),

  closeWorkbook1,
};

Perhaps a related question since I'm talking about activity on the "root" object, is how I might subscribe to any change on my deepsignal?

I'd like to implement a logger or undo/redo capability with my state object as a whole, rather than individual properties.

You can't do this, you're reassigning the store.state reference to a plain object and breaking all the signals references:

const closeWorkbook1 = () => {
    store.state = initialState;
}

You need to maintain the initial reference. Use something like Object.assing:

const closeWorkbook1 = () => {
  Object.assign(store.state, initialState);
}

I made a PR to add tests for this and a new section in the docs:

Perhaps a related question since I'm talking about activity on the "root" object, is how I might subscribe to any change on my deepsignal?

A common trick is to use JSON.stringify, which basically subscribes deeply to all properties, but for your use case you probably would need to deep clone it anyway to be able to restore it later in that state, so that would suffice because the deep clone will also access all the properties:

effect(() => {
  saveState(deepClone(store.state));
});