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?
+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. 馃憤
Most helpful comment
Ok, so...
And with the dependency array...
And with the config...
I think you are right. Best to optimise for the common case. 馃憤