@solid-hooks/core v0.4.1
@solid-hooks/core
useful hooks for solid.js
!WARNING Breaking change expected. Use at your own risk.
Install
npm i @solid-hooks/core
yarn add @solid-hooks/core
pnpm add @solid-hooks/core
Usage
createRef
read / write signal in one function
import { createRef } from '@solid-hooks/core'
import { onMounted } from 'solid-js'
function Test() {
const divRef = createRef<HTMLDivElement>()
return <div ref={divRef} />
}
function Counter() {
const counter = createRef(0)
return <button onClick={() => counter(c => c + 1)}>{counter()}</button>
}
function useSomethingRef() {
return createRef(useSomething())
}
createTracker
Track plain object property, make it reactive
import { createTracker } from '@solid-hooks/core'
const audio = new Audio()
const [time, setCurrentTime] = createTracker(audio, 'currentTime')
Before v0.4.0 is createReactive
createArray
create array signal
import { createArray } from '@solid-hooks/core'
const [array, setArray] = createArray(['a', 'b', 'c'])
const push = setArray(l => l.push('d'))
const pop = setArray(l => l.pop())
const reset = setArray(['a', 'b', 'c'])
createToggle
create toggle signal
import { createToggle } from '@solid-hooks/core'
const [state, toggle] = createToggle(
false,
value => console.log(value)
)
toggle()
toggle(true)
toggle(false)
createDirective
another way to create directive
import { createDirective } from '@solid-hooks/core'
import { type Accessor, createRenderEffect, createSignal, type Setter } from 'solid-js'
const model = createDirective((ref: Element, getter: Accessor<string>, setter: Setter<string>) => {
createRenderEffect(() => ((ref as HTMLInputElement).value = getter()))
ref.addEventListener('input', e => setter((e.target as HTMLInputElement | null)?.value ?? ''))
})
function TextInput() {
const [text, setText] = createSignal('')
return (
<>
<input type="text" ref={model(text, setText)} />
<div>{text()}</div>
</>
)
}
reference from voby
watch
filterable and pausable createEffect(on())
like, defer by default
import { watch } from '@solid-hooks/core'
import { throttle } from '@solid-primitives/scheduled'
const [count, setCount] = createSignal(0)
const { pause, resume, isWatching, callTimes, ignoreUpdate } = watch(
count,
(value, oldValue, callTimes) => {
console.log(value, oldValue, callTimes)
const cleanup = () => { }
return cleanup
},
{
eventFilter: fn => throttle(fn, 100),
count: 5,
defer: false /* true by default */
}
)
watchOnce
watch once, using createReaction
import { watchOnce } from '@solid-hooks/core'
const [count, setCount] = createSignal(0)
watchOnce(count, console.log)
watchImmediate
like watch
, use createComputed
watchRendered
like watch
, use createRendered
useEmits
like defineEmits
in Vue
, emit event from child component
import { type defineEmits, useEmits } from '@solid-hooks/core'
type Emits = defineEmits<{
// sync
var: number
update: [d1: string, d2?: string, d3?: string]
// sync or async
fn: (test: string) => void
}>
function Child(prop: Emits & { num: number }) {
const emit = useEmits(prop)
const handleClick = () => {
emit('var', { id: 1 })
emit('update', `emit from child: ${prop.num}`, 'second param')
emit('fn', ['a', 'b'])
}
return (
<div>
<div>
child prop: {prop.num}
</div>
<button onClick={handleClick}>click and see console</button>
</div>
)
}
export default function Father() {
return (
<Child
num={1}
$var={e => console.log('[emit] $var:', e)}
$update={(d, d1) => console.log(`[emit] $update:`, d, d1)}
$fn={test => console.log('[emit] $fn:', test)}
/>
)
}
createApp
like createApp()
in Vue
import { createApp } from '@solid-hooks/core'
import App from './App'
createApp(App)
.use(RouterProvider, { props })
.use(I18nProvider)
.use(GlobalStoreProvider)
.mount('#app')
is equal to:
render(
<RouterProvider props={props}>
<I18nProvider>
<GlobalStoreProvider>
<App />
</GlobalStoreProvider>
</I18nProvider>
</RouterProvider>,
document.querySelector('#app')
)
reference from solid-utils
createContextProvider
reference from @solid-primitives/context
if default value is not defined and use context outside provider, throw Error
when DEV
import { createContextProvider } from '@solid-hooks/core'
import { createSignal } from 'solid-js'
export const [TestProvider, useTestContext] = createContextProvider((param: { initial: number }) => {
const [count, setCount] = createSignal(param.initial)
const increment = () => setCount(count() + 1)
return { count, increment }
})
function Child() {
const { count, increment } = useTestContext()
return (
<button onClick={increment}>
{count()}
</button>
)
}
export function TestContextProvider() {
console.log('call useTestContext() outside provider:', useTestContext())
return (
<TestProvider initial={0}>
<Child />
</TestProvider>
)
}
useCallback
create callbacks with runWithOwner
, auto get current owner
reference from @solid-primitives/rootless
import { useCallback } from '@solid-hooks/core'
const handleClick = useCallback(() => {
console.log('after 100 ms!')
})
setTimeOut(handleClick, 100)
@solid-hooks/core/web
cls
merge classes, lightweight version of clsx
import { cls } from '@solid-hooks/core/web'
cls('foo', true && 'bar', false && ['bar', true && 'baz'], 1)
// => 'foo baz'
useHover
check if element is hovered
import { useHover } from '@solid-hooks/core/web'
function App() {
let el
const [hovered] = useHover(() => el)
return <div ref={el}>{hovered() ? 'hovered' : 'not hovered'}</div>
}
useClickOutside
check if element is clicked outside
import { useClickOutside } from '@solid-hooks/core/web'
function App() {
let el
const [isClickOutside] = useClickOutside(() => el)
return <div ref={el}>{isClickOutside() ? 'clicked outside' : 'clicked inside'}</div>
}
useLongPress
check if element is long pressed
import { useLongPress } from '@solid-hooks/core/web'
function App() {
let el
const [isLongPress] = useLongPress(() => el)
return <div ref={el}>{isLongPress() ? 'long pressed' : 'not long pressed'}</div>
}
useTitle
reactive document title
import { useTitle } from '@solid-hooks/core/web'
const [title, setTitle] = useTitle()
// or with external signal
const [title, setTitle] = createSignal('')
useTitle(title)
setTitle('new title')
createObjectURL
convert blob
/ File
/ MediaSource
/ ArrayBuffer
/ ArrayBufferView
/ string
to signal URL, auto revoke on cleanup
import { createObjectURL } from '@solid-hooks/core/web'
const [source, setMediaSource, cleanupSource] = createObjectURL(new MediaSource())
const [url, setURL, cleanupURL] = createObjectURL(new Uint8Array(8), { type: 'image/png' })
useWorkerFn
run function in worker, support local functions or external dependencies
reference from vueuse
import { useWebWorkerFn } from '@solid-hooks/core/web'
import { createMemo, createSignal } from 'solid-js'
const randomNumber = () => Math.trunc(Math.random() * 5_000_00)
function heavyTask() {
const numbers: number[] = Array.from({ length: 5_000_000 }).fill(undefined).map(randomNumber)
numbers.sort()
return numbers.slice(0, 5)
}
export default function TestWorker() {
const [fn, { status, terminate }] = useWebWorkerFn(heavyTask, { func: [randomNumber] })
const isRunning = createMemo(() => status() === 'RUNNING')
return (
<>
<div>Status: {status()}</div>
<button onClick={() => isRunning() ? terminate() : fn().then(setData)}>
{isRunning() ? 'terminate' : 'sort in worker'}
</button>
</>
)
}
useExternal
load external CSS/JS
import { useExternal } from '@solid-hooks/core/web'
const script = 'console.log(`test load script`)'
const [scriptElement, cleanupScript] = useExternal('script', script, {/* options */})
const [styleElement, cleanupStyle] = useExternal('style', style, {/* options */})
useEventListener
/ useEventListenerStack
/ useDocumentListener
/ useWindowListener
auto cleanup event listener, allow nullish target
reference from @solid-primitives/event-listener
useMediaQuery
create media query signal
import { useMediaQuery, usePrefersDark } from '@solid-hooks/core/web'
const isLg = useMediaQuery('(min-width: 1024px)')
const isDark = usePrefersDark()
useColorMode
auto color mode with attribute toggle, disable transition by default
import { useColorMode } from '@solid-hooks/core/web'
export default function TestColorMode() {
const [mode, setMode, isDark] = useColorMode()
return (
<>
<div>{isDark() ? 'dark' : 'light'} theme</div>
<div>{mode()}</div>
<button onClick={() => setMode(m => m === 'dark' ? 'light' : 'dark')}>click</button>
</>
)
}
useNetwork
signals of network status, with onChanges
callback
import { useNetwork } from '@solid-hooks/core/web'
const net = useNetwork()
const isOnline = net.online
types:
type NetworkType = 'bluetooth' | 'cellular' | 'ethernet' | 'none' | 'wifi' | 'wimax' | 'other' | 'unknown'
type EffectiveType = 'slow-2g' | '2g' | '3g' | '4g'
export type NetworkState = {
/**
* the time at which the connection was changed
*/
since?: Date
/**
* whether the device is online
*/
online?: boolean
/**
* the estimated effective round-trip time of the current connection
*/
rtt?: number
/**
* type of connection a device is using to communicate with the network
*/
type?: NetworkType
/**
* true if the user has set a reduced data usage option on the user agent
*/
saveData?: boolean
/**
* the estimated effective bandwidth (Mb/s)
*/
downlink?: number
/**
* maximum downlink speed (Mb/s)
*/
downlinkMax?: number
/**
* the effective type of the connection
*/
effectiveType?: EffectiveType
}
useIdleCallback
executes a callback using the requestIdleCallback
API, fallback to setTimeout
.
auto cleanup, return cleanup function.
see https://developer.mozilla.org/zh-CN/docs/Web/API/Background_Tasks_API
useCssVar
bind css variable to signal
import { useCssVar } from '@solid-hooks/core/web'
const [color, setColor] = createSignal('red')
useCssVar('bg', color)
useCopy
/ usePaste
/ createClipboardItem
hooks that paste from clipboard
import { createClipboardItem, useCopy, usePaste } from '@solid-hooks/web'
export default () => {
const [data, setData] = createClipboardItem('test')
const { isCopied, copy } = useCopy()
const paste = usePaste({
onPaste: (data, mime) => console.log(data, mime)
})
return (
<>
<div>is copied: {isCopied() ? 'true' : 'false'}</div>
<button onClick={() => copy(data())}>copy</button>
<button onClick={paste}>paste</button>
</>
)
}
License
MIT
3 months ago
4 months ago
8 months ago
6 months ago
8 months ago
7 months ago
8 months ago
5 months ago
7 months ago
7 months ago
7 months ago
8 months ago
7 months ago
8 months ago
8 months ago
9 months ago
9 months ago
9 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
11 months ago
12 months ago
12 months ago
1 year ago