-
React-inspired hooks for reactive state management.
-
install
hmmfirst.hmm i @minejs/hooks
-
import { useState, useEffect, useSignal } from '@minejs/hooks'
-
// Setup hook context in your component const context = { hooks: [], currentHookIndex: 0, component: {} } setHookContext(context) // Create state const [count, setCount] = useState(0) // Read value console.log(count()) // 0 // Update value setCount(5) console.log(count()) // 5 // Update with function setCount(prev => prev + 1) console.log(count()) // 6
-
const [name, setName] = useState('John') // Effect runs when dependencies change useEffect(() => { console.log('Hello,', name()) // Optional cleanup return () => { console.log('Cleaning up...') } }, [name])
-
const items = signal([1, 2, 3]) // Memoized computation const total = useMemo(() => { return items().reduce((a, b) => a + b, 0) }, [items()]) console.log(total()) // 6
-
const count = useRef(0) count.current = 5 console.log(count.current) // 5 (persists across renders)
-
-
-
-
Create reactive state with update function.
const [count, setCount] = useState(0) count() // Read: 0 setCount(5) // Write: 5 setCount(n => n + 1) // Update: 6
-
Run side effects when dependencies change.
useEffect(() => { console.log('Effect ran!') // Optional cleanup return () => { console.log('Cleanup!') } }, [dependency])
-
Memoize expensive computations.
const expensiveValue = useMemo(() => { return complexCalculation(data) }, [data])
-
Memoize function references.
const handleClick = useCallback(() => { setCount(prev => prev + 1) }, [])
-
Create persistent reference that survives renders.
const inputRef = useRef<HTMLInputElement>(null) inputRef.current?.focus()
-
Complex state management with reducer pattern.
type Action = { type: 'INC' } | { type: 'DEC' } const [state, dispatch] = useReducer(reducer, 0) dispatch({ type: 'INC' })
-
Access context values.
const theme = useContext(ThemeContext)
-
Create native signal (CruxJS integration).
const sig = useSignal(0) sig.set(5) sig.update(n => n + 1)
-
Create derived signal from other signals.
const doubled = useComputed(() => count() * 2)
-
Toggle boolean state.
const [isOpen, toggle] = useToggle(false) toggle() // true toggle() // false
-
useCounter(initialValue?: number): { count: Signal<number>, increment: () => void, decrement: () => void, reset: () => void }Counter with increment/decrement/reset.
const counter = useCounter(0) counter.increment() counter.decrement() counter.reset()
-
Persist state to localStorage.
const [saved, setSaved] = useLocalStorage('user', {})
-
Debounce value changes.
const debouncedSearch = useDebounce(searchInput, 300)
-
Run callback at interval.
useInterval(() => { console.log('Every second!') }, 1000)
-
Get current window dimensions.
const size = useWindowSize() console.log(size.width, size.height)
-
Check media query matches.
const isMobile = useMediaQuery('(max-width: 768px)')
-
useEventListener<K extends keyof WindowEventMap>(eventName: K, handler: (event: WindowEventMap[K]) => void, element?: Window | HTMLElement): voidAttach event listeners.
useEventListener('click', (e) => { console.log('Clicked!') })
-
-
-
import { useState, setHookContext } from '@minejs/hooks' function Counter() { const context = { hooks: [], currentHookIndex: 0, component: {} } setHookContext(context) const [count, setCount] = useState(0) const button = document.createElement('button') button.textContent = `Count: ${count()}` button.onclick = () => setCount(prev => prev + 1) return button }
-
import { useState, useEffect, useMemo } from '@minejs/hooks' interface Todo { id: number text: string done: boolean } const [todos, setTodos] = useState<Todo[]>([]) const [filter, setFilter] = useState<'all' | 'active' | 'completed'>('all') const filteredTodos = useMemo(() => { const f = filter() const t = todos() if (f === 'active') return t.filter(todo => !todo.done) if (f === 'completed') return t.filter(todo => todo.done) return t }, [filter(), todos()]) // Actions function addTodo(text: string) { setTodos(list => [ ...list, { id: Date.now(), text, done: false } ]) } function toggleTodo(id: number) { setTodos(list => list.map(todo => todo.id === id ? { ...todo, done: !todo.done } : todo ) ) }
-
import { useState, useMemo, useEffect } from '@minejs/hooks' const [email, setEmail] = useState('') const [password, setPassword] = useState('') const isEmailValid = useMemo(() => { return email().includes('@') && email().length > 3 }, [email()]) const isPasswordValid = useMemo(() => { return password().length >= 8 }, [password()]) const canSubmit = useMemo(() => { return isEmailValid() && isPasswordValid() }, [isEmailValid(), isPasswordValid()]) useEffect(() => { const button = document.querySelector('#submit') as HTMLButtonElement if (button) button.disabled = !canSubmit() }, [canSubmit()])
-
import { useState, useEffect, useDebounce } from '@minejs/hooks' const [searchTerm, setSearchTerm] = useState('') const debouncedTerm = useDebounce(searchTerm, 300) useEffect(() => { if (!debouncedTerm) return // Fetch search results fetch(`/api/search?q=${debouncedTerm}`) .then(r => r.json()) .then(results => setResults(results)) }, [debouncedTerm])
-
-
Notifications
You must be signed in to change notification settings - Fork 0
React-inspired hooks for reactive state management.
License
minejs-org/hooks
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
 |  | |||
 |  | |||
 |  | |||
 |  | |||
 |  | |||
 |  | |||
 |  | |||
 |  | |||
 |  | |||
 |  | |||
 |  | |||
 |  | |||
 |  | |||
 |  | |||
 |  | |||
 |  | |||
Repository files navigation
About
React-inspired hooks for reactive state management.

