https://github.com/thetarnav/solid-watch-primitives
An experimental collection of reactive helpers built around watching computation changes. Inspired by: https://vueuse.org/functions.html#watch. Made For: https://github.com/davedbase/solid-primitives
https://github.com/thetarnav/solid-watch-primitives
effects primitives solid watch
Last synced: 18 days ago
JSON representation
An experimental collection of reactive helpers built around watching computation changes. Inspired by: https://vueuse.org/functions.html#watch. Made For: https://github.com/davedbase/solid-primitives
- Host: GitHub
- URL: https://github.com/thetarnav/solid-watch-primitives
- Owner: thetarnav
- License: mit
- Created: 2021-11-14T13:11:57.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2021-11-16T21:13:56.000Z (over 4 years ago)
- Last Synced: 2026-05-04T00:09:26.229Z (about 2 months ago)
- Topics: effects, primitives, solid, watch
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/solid-watch-primitives
- Size: 190 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# solid-watch-primitives
#### This package is experimental, made to test the concept and usability of primitives build around watching computation changes, to see how it can be used in [Solid](https://www.solidjs.com/). Eventually to be merged to [solid-primitives](https://github.com/davedbase/solid-primitives) if proven useful.
#### Feel free to play around with it, I would appreciate any feedback or ideas that you may have, you can join the discussion [here](https://github.com/davedbase/solid-primitives/pull/19) or simply open an issue if you have some opinions to share.
#### The original idea and parts of the used logic comes from [Anthony Fu's vueuse library](https://github.com/vueuse/vueuse) for Vue.
[try on codesandbox](https://codesandbox.io/s/solid-watch-primitives-urb2u?file=/src/index.tsx)
## The Usage:
### Installation:
```sh
npm i solid-watch-primitives
```
### Available Primitives:
```ts
import { createFilteredEffect, createFilter, until } from 'solid-watch-primitives'
```
### createFilteredEffect
When used alone, it's a shortcut for `createEffect(on(source, fn))`. But it can be combined with [Filters](#available-filters) to extend it's functionality.
```ts
const [counter, setCounter] = createSignal(0)
// alone:
createFilteredEffect(counter, n => console.log(n))
// accepts "defer" option, same as on()
createFilteredEffect(counter, n => console.log(n), { defer: true })
// with filter:
createFilteredEffect(debounced(counter, n => console.log(n), { wait: 300 }))
// with nested filters:
const { stop, pause } = createFilteredEffect(stoppable(pausable(counter, n => console.log(n))))
```
### createFilter
A utility for creating your own custom filters. Every available filter was made using this.
```ts
function createFilter(
modifier: (
source: Fn | Fn[], // like source of "on"
callback: EffectCallback, // like callback of "on"
config: Config, // config for your filter
stop: StopEffect | undefined, // a StopEffect if RequireStop
) => [CustomCallback, Returns], // return your modified callback and custom return values
requireStop?: RequireStop, // true if you want to use StopEffect
): Filter {}
// for example, thats the source of "debounce"
const debounce = createFilter<{
wait: number
}>((s, fn, options) => {
const [_fn, clear] = _debounce(fn, options.wait)
onCleanup(clear)
return [_fn, {}]
})
// and this is "atMost", notice the required double "true" to use stop
const atMost = createFilter<
{ limit: MaybeAccessor }, // config you require
{ count: Accessor }, // what you want to return
true // if you want to use stop()
>(
(s, callback, config, stop) => {
const [count, setCount] = createSignal(0)
const _fn = (...a: [any, any, any]) => {
setCount(p => p + 1)
count() + 1 >= access(config.limit) && stop()
callback(...a)
}
return [_fn, { count }] // [CustomCallback, Returns]
},
true, // if you want to use stop()
)
```
### until
`until` instead of being a simple shortcut, this one solves an actual problem.
The problem is that, when you use someting like `createFetch` to abstract an asynchronous operation into a reactive helper, you loose the option to use `await`. Because you are turning Promise into a Signal. The `until` tries to brings that functionality back.
```ts
const [data] = createFetch('https://my-url/')
await until(data).not.toBeNull()
console.log(data)
```
[More until usage here](https://vueuse.org/shared/until/#usage)
### Available Filters
```ts
import {
stoppable,
once,
atMost,
debounce,
throttle,
whenever,
pausable,
ignorable,
} from 'solid-watch-primitives'
```
### stoppable
returns `{ stop: StopEffect }`, that can be used to manually dispose of the effects.
```ts
const { stop } = createFilteredEffect(stoppable(counter, n => console.log(n)))
```
### once
disposes itself on the first captured change. **Set the defer option to true**, otherwise the callback will run and dispose itself on the initial setup.
```ts
createFilteredEffect(
once(counter, n => console.log(n)),
{ defer: true },
)
```
### atMost
you specify the number of times it can triggered, until disposes itself.
```ts
const { count } = createFilteredEffect(atMost(counter, n => console.log(n), { limit: 8 }))
```
### debounce
debounces callback
```ts
const position = createScrollObserver()
createFilteredEffect(debounce(position, x => console.log(x), { wait: 300 }))
```
### throttle
The callback is throttled
```ts
const position = createScrollObserver()
createFilteredEffect(throttle(position, x => console.log(x), { wait: 300 }))
```
### whenever
Runs callback each time the source is truthy.
```ts
setInterval(() => setCount(p => p + 1), 1000)
createFilteredEffect(
whenever(
() => count() > 5,
() => console.log(count()),
),
)
// will fire on each count change, if count is gt 5
// => 6, 7, 8, 9, 10, ...
createFilteredEffect(
whenever(
createMemo(() => count() > 5),
() => console.log(count()),
),
)
// will fire only when the memo changes
// => 6
```
### pausable
Manually controll if the callback gets to be executed
```ts
const { pause, resume, toggle } = createFilteredEffect(
pausable(counter, x => console.log(x), { active: false }),
)
```
### ignorable
Somewhat similar to `pausable`, but ignore changes that would cause the next effect to run.
Because Solid batches together changes made in effects, the usage inside and outside effects will differ.
```ts
const { ignoreNext, ignoring } = createFilteredEffect(ignorable(
counter,
x => {
// next effect will be ignored:
ignoreNext()
setCounter(p => p + 1)
// this change happens in the same effect, so it will also be ignored
setCounter(5)
}
));
const ignoreMe = () => {
ignoring(() => {
// both changes will be ignored:
setCounter(420)
setCounter(69)
})
// but not this one:
setCounter(p => p + 2)
}
// this watcher will work normally,
// ignoring only affects the ignorableWatch above
createFilteredEffect(counter, () => {...})
```