S
SolidJS2w ago
Ryan

Should custom stores have embedded effects like this?

So lets have I have a custom store to manage updating a value and a debounce version (so that an expensive action can trigger on the debounce value) like this:
import { debounce } from 'lodash';
import { type Accessor, createEffect, createSignal } from 'solid-js';

const createDebouncedUpdateStore = (options: DebouncedUpdateStoreOptions = {}): DebouncedUpdateStore => {
const [displayValue, setDisplayValue] = createSignal<string>(options.defaultDisplayValue ?? '');
const [debouncedValue, internalSetDebouncedValue] = createSignal<string>(options.defaultDisplayValue ?? '');

const setDebouncedValue = debounce((value: string) => {
internalSetDebouncedValue(value);
}, options.debounceTime ?? 350);

createEffect(function displayValueUpdated() {
options.onDisplayValueChanged?.(displayValue());
});

createEffect(function debouncedValueUpdated() {
options.onDebouncedValueChanged?.(debouncedValue());
});

return {
displayValue,
setDisplayValue,
debouncedValue,
setDebouncedValue,
};
};

export const debouncedUpdateStoreUtils = {
createStore: createDebouncedUpdateStore,
};
import { debounce } from 'lodash';
import { type Accessor, createEffect, createSignal } from 'solid-js';

const createDebouncedUpdateStore = (options: DebouncedUpdateStoreOptions = {}): DebouncedUpdateStore => {
const [displayValue, setDisplayValue] = createSignal<string>(options.defaultDisplayValue ?? '');
const [debouncedValue, internalSetDebouncedValue] = createSignal<string>(options.defaultDisplayValue ?? '');

const setDebouncedValue = debounce((value: string) => {
internalSetDebouncedValue(value);
}, options.debounceTime ?? 350);

createEffect(function displayValueUpdated() {
options.onDisplayValueChanged?.(displayValue());
});

createEffect(function debouncedValueUpdated() {
options.onDebouncedValueChanged?.(debouncedValue());
});

return {
displayValue,
setDisplayValue,
debouncedValue,
setDebouncedValue,
};
};

export const debouncedUpdateStoreUtils = {
createStore: createDebouncedUpdateStore,
};
From a patterns standpoint, does it make sense to instead of having the consumer of this store have do this:
const debounceUpdateStore = debouncedUpdateStoreUtils.createStore();
// other code...
createEffect(function debouncedValueUpdated() {
setRequestData((previousData) => ({
...previousData,
search: debounceUpdateStore.debouncedValue(),
}));
});
const debounceUpdateStore = debouncedUpdateStoreUtils.createStore();
// other code...
createEffect(function debouncedValueUpdated() {
setRequestData((previousData) => ({
...previousData,
search: debounceUpdateStore.debouncedValue(),
}));
});
you allow them do something like this:
const debounceUpdateStore = debouncedUpdateStoreUtils.createStore({
onDebouncedValueChanged: (value) => {
setRequestData((previousValue) => ({ ...previousValue, search: value }));

listQuery.refetch();
},
});
const debounceUpdateStore = debouncedUpdateStoreUtils.createStore({
onDebouncedValueChanged: (value) => {
setRequestData((previousValue) => ({ ...previousValue, search: value }));

listQuery.refetch();
},
});
Does this come down to personal preference or are there bigger pros / cons between these two approaches (the benefit of the embedded is the the effect and creation of the store is in one place)?
1 Reply
bigmistqke
bigmistqke2w ago
i would do the following:
const { debouncedValue, onDebouncedUpdate } = createDebouncedStore(...)
onDebouncedUpdate(updateRequestData)
const { debouncedValue, onDebouncedUpdate } = createDebouncedStore(...)
onDebouncedUpdate(updateRequestData)
if you want to add it to the declaration i would probably do the following:
const { ... } = createDebouncedStore(initialValue, { onDebouncedUpdate(value){ ... } })
const { ... } = createDebouncedStore(initialValue, { onDebouncedUpdate(value){ ... } })
with a second options-object a, now that i read the question a bit better: not including the listener is also a fair option createSignal also does not have an onUpdate listener, for example one suggestion tho: I would not call your primitive a store. in solid a store implies that it is fine-grained, like solid's createStore, but your primitive is a signal instead.

Did you find this page helpful?