Easy-peasy: Introduce useLocalStore API, deprecate useComponentStore

Created on 17 Mar 2020  路  2Comments  路  Source: ctrlplusb/easy-peasy

Howdy all;

So, after some use and feedback I believe the the useComponentStore API is verbose and doesn't lend itself to more dynamic composition.

I am playing with a new API in mind and would like to get some feedback from the community before proceeding to build it out.

import { useLocalStore, createStore, action } from 'easy-peasy';

export default function Counter() {
  const [state, actions] = useLocalStore(() => createStore({
    counter: 0,
    increment: action(_state => {
      _state.counter += 1;
    })
  }));

  return (
    <div>
      <h1>{state.counter</h1>
      <button onClick={() => actions.increment()}>Increment</button>
    </div>
  );
}

As you can see, you use the new API as a hook directly within your component. You need to provide a function that returns a new store instance.

This may appear slightly verbose at first appearance, however, using this approach allows me to support a secondary argument which would be a dependency array. Should one of the dependencies change, then the function would be executed again in order to create a new store instance.

function EditProduct({ id, name }) {
  const [state, actions] = useLocalStore(
    () => createStore({
      id,
      name,
      editName: action((_state, payload) => {
        _state.name = payload;
      }),
    }),
    [id, name]
  );

  // ...
}

As you can see in this example, we have a component used to edit a products details. Every time the incoming props change we reinitialise the store, thereby representing the editing for a different product.

In addition to this, explicitly requiring that you use the createStore API allows you to provide a custom configuration to the underlying store.

Thoughts?

feedback-wanted new-feature

Most helpful comment

Ok, so...

export default function Counter() {
  const [state, actions, store] = useLocalStore(() =>({
    counter: 0,
    increment: action(_state => {
      _state.counter += 1;
    })
  }));

  // ...
}

And with the dependency array...

function EditProduct({ id, name }) {
  const [state, actions] = useLocalStore(
    () => ({
      id,
      name,
      editName: action((_state, payload) => {
        _state.name = payload;
      }),
    }),
    [id, name]
  );

  // ...
}

And with the config...

function EditProduct({ id, name }) {
  const [state, actions] = useLocalStore(
    () => ({
      id,
      name,
      editName: action((_state, payload) => {
        _state.name = payload;
      }),
    }),
    [id, name],
    {
       name: 'EditProductStore'
    }
  );

  // ...
}

I think you are right. Best to optimise for the common case. 馃憤

All 2 comments

+1 for the additional store config control that could be super handy. I don't mind the extra verbosity, just curious is there ever a use case where you wouldn't be returning a createStore? If it's always a store you could probably just do 3 params with the first param a "mixin/model helper" function to make it feel less verbose and abstract that createStore as part of the useLocalStore.

 const [state, actions] = useLocalStore(mixinFunc, dependancies, optionalStoreConfig);

I put storeConfig last since I feel like in local state it's prob less likely to be configured. It does make it feel less hooky though.

Also seeing your example makes me really wonder why I didn't set up all my "editing" with component stores. Now my code feels mucky...

Ok, so...

export default function Counter() {
  const [state, actions, store] = useLocalStore(() =>({
    counter: 0,
    increment: action(_state => {
      _state.counter += 1;
    })
  }));

  // ...
}

And with the dependency array...

function EditProduct({ id, name }) {
  const [state, actions] = useLocalStore(
    () => ({
      id,
      name,
      editName: action((_state, payload) => {
        _state.name = payload;
      }),
    }),
    [id, name]
  );

  // ...
}

And with the config...

function EditProduct({ id, name }) {
  const [state, actions] = useLocalStore(
    () => ({
      id,
      name,
      editName: action((_state, payload) => {
        _state.name = payload;
      }),
    }),
    [id, name],
    {
       name: 'EditProductStore'
    }
  );

  // ...
}

I think you are right. Best to optimise for the common case. 馃憤

Was this page helpful?
0 / 5 - 0 ratings