cefn / watchable

Repo for @watchable/store and supporting packages.
MIT License
5 stars 1 forks source link

Create read/write utility hook like React useState #40

Closed cefn closed 9 months ago

cefn commented 10 months ago

I take it from https://github.com/cefn/watchable/issues/37 that a signature having the capabilities of React.useState to permit reading and writing of a value within Store state would be valuable.

The useSelected hook easily permits retrieving any property from the state, but this doesn't assist with a setter definition, which is impossible to derive from a selector which is just a black-box function.

The natural primitive operation (at least until path support is introduced) is to use a key from one of the state's child properties which can define BOTH a selector and a setter.

In this MR, we introduce a useStateProperty hook, with a signature similar to useState, driven by a keyed property of the Store state. Draft implementation is here and tests are here

For example this would display first red then white after the useEffect change of state has triggered a futher render...

      const store = createStore({ roses: "red" });
      const Component = () => {
        const [roseColor, setRoseColor] = useStateProperty(store, "roses");
        useEffect(() => {
          setRoseColor("white");
        }, []);
        return <p>{roseColor}</p>;
      };

Alternative: Using createStorePartition()

It is not suitable to use createStorePartition as a backing implementation, even though this seems promising since you can pick an individual property, read it and write it using the partitioned Store read/write methods. That's because it comes with a lot of overhead (creates a whole store, with its own listener list, and irreversibly subscribes the store to the parent store).

As summarised here the store-partitioning pattern is intended much more for single-responsibility and interface-segregation. It means components can consume a complete store interface (including watch) without knowing that it's actually a sub-part of a larger Store, and multiple subscribers can then benefit from the efficiency of having ALL their watch subscriptions eliminated by a single check (that their partition of the store hasn't changed).

These aren't requirements of the case described by https://github.com/cefn/watchable/issues/37

Also until the implementation of https://github.com/cefn/watchable/issues/36 the creation of store partitions can't be undone (there is no destroy that detaches watchers) meaning this kind of derived state is poorly managed as part of a React render and could lead to memory leaks.

Closes #37