hookstate icon indicating copy to clipboard operation
hookstate copied to clipboard

Partial Updates (Scoped State) with Classes

Open zroug opened this issue 1 year ago • 1 comments

Is there a way to get partial updates working when using classes instead of plain objects?

Consider the following example:

import React from 'react';
import { useHookstate } from "@hookstate/core";

class AppState {
  constructor() {
    this.a = 0;
    this.b = 0;
  }
}

export function App() {
  const state = useHookstate(new AppState())
  return (
    <div>
      <p>{new Date().toISOString().toString()}: {state.a.get()}</p>
      <Component count={state.b} />
    </div>
  );
}

function Component(props) {
  const count = useHookstate(props.count)
  return (
    <>
      <p>{new Date().toISOString().toString()}: {count.get()}</p>
      <button onClick={() => count.set(count => count + 1)}>Count</button>
    </>
  );
}

Here, both the parent component and the child component get updated when the button is clicked. When new AppState() is replaced with { a: 0, b: 0 }, only the child component gets updated. Is there a way to get the behavior from the plain object state while using a class object? I'm fully aware that Hookstate won't be able to catch every update when more advanced class features like getters and methods are used, but I'm willing to handle these cases myself.

I would like to use Hookstate to model the UI around an existing app state instead of duplicating the state for the UI, but this won't work if on every change the whole UI gets updated. Most of the app state behaves like a plain object, the class is mostly used for data validation and stuff like that.

The documentation of Hookstate says, that for non-plain objects, get() gets replaced with get({ noproxy: true }). I'm fine with that, but I think in the example above something else is going on because when I replace new AppState() with { a: 0, b: 0 } and both get calls with get({ noproxy: true }), the partial update still works.

Example Class State: https://playcode.io/1047463 Example Plain Object State: https://playcode.io/1047469 Example Plain Object State with { noproxy: true }: https://playcode.io/1047470

zroug avatar Dec 28 '22 23:12 zroug

Theoretically, it could be possible to implement a new option for configure function, which would allow to define callback, which would define per each variable of a custom class if it should be returned as a proxy or not. Then this callback could be invoked on get where it tests Object's class name. Very easy addition, please consider to contribute. I will help.

avkonst avatar Mar 31 '23 08:03 avkonst