Skip to content

React-inspired hooks for reactive state management.

License

Notifications You must be signed in to change notification settings

minejs-org/hooks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation


logo


Test Coverage Github Repo Issues GitHub Repo stars

  • Quick Start 🔥

    React-inspired hooks for reactive state management.

    • Setup

      install hmm first.

      hmm i @minejs/hooks
    line
    • Usage

      import { useState, useEffect, useSignal } from '@minejs/hooks'
      • 1. useState - Stateful Values

        // 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
      • 2. useEffect - Side Effects

        const [name, setName] = useState('John')
        
        // Effect runs when dependencies change
        useEffect(() => {
            console.log('Hello,', name())
        
            // Optional cleanup
            return () => {
                console.log('Cleaning up...')
            }
        }, [name])
      • 3. useMemo - Memoized Values

        const items = signal([1, 2, 3])
        
        // Memoized computation
        const total = useMemo(() => {
            return items().reduce((a, b) => a + b, 0)
        }, [items()])
        
        console.log(total()) // 6
      • 4. useRef - Persistent References

        const count = useRef(0)
        
        count.current = 5
        console.log(count.current) // 5 (persists across renders)

  • API Reference 🔥

    • useState<T>(initialValue: T): [Signal<T>, (action: SetStateAction<T>) => void]

      Create reactive state with update function.

      const [count, setCount] = useState(0)
      
      count()              // Read: 0
      setCount(5)          // Write: 5
      setCount(n => n + 1) // Update: 6
    • useEffect(callback: () => void | (() => void), deps?: DependencyList): void

      Run side effects when dependencies change.

      useEffect(() => {
          console.log('Effect ran!')
      
          // Optional cleanup
          return () => {
              console.log('Cleanup!')
          }
      }, [dependency])
    • useMemo<T>(factory: () => T, deps: DependencyList): T

      Memoize expensive computations.

      const expensiveValue = useMemo(() => {
          return complexCalculation(data)
      }, [data])
    • useCallback<T extends (...args: any[]) => any>(callback: T, deps: DependencyList): T

      Memoize function references.

      const handleClick = useCallback(() => {
          setCount(prev => prev + 1)
      }, [])
    • useRef<T>(initialValue: T): { current: T }

      Create persistent reference that survives renders.

      const inputRef = useRef<HTMLInputElement>(null)
      inputRef.current?.focus()
    • useReducer<S, A>(reducer: Reducer<S, A>, initialState: S): [Signal<S>, (action: A) => void]

      Complex state management with reducer pattern.

      type Action = { type: 'INC' } | { type: 'DEC' }
      const [state, dispatch] = useReducer(reducer, 0)
      dispatch({ type: 'INC' })
    • useContext<T>(context: Context<T>): T

      Access context values.

      const theme = useContext(ThemeContext)
    • useSignal<T>(initialValue: T): Signal<T>

      Create native signal (CruxJS integration).

      const sig = useSignal(0)
      sig.set(5)
      sig.update(n => n + 1)
    • useComputed<T>(fn: () => T): Signal<T>

      Create derived signal from other signals.

      const doubled = useComputed(() => count() * 2)
    • useToggle(initialValue?: boolean): [Signal<boolean>, () => void]

      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()
    • useLocalStorage<T>(key: string, initialValue: T): [Signal<T>, (value: T) => void]

      Persist state to localStorage.

      const [saved, setSaved] = useLocalStorage('user', {})
    • useDebounce<T>(value: T, delay: number): T

      Debounce value changes.

      const debouncedSearch = useDebounce(searchInput, 300)
    • useInterval(callback: () => void, delay: number | null): void

      Run callback at interval.

      useInterval(() => {
          console.log('Every second!')
      }, 1000)
    • useWindowSize(): { width: number, height: number }

      Get current window dimensions.

      const size = useWindowSize()
      console.log(size.width, size.height)
    • useMediaQuery(query: string): boolean

      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): void

      Attach event listeners.

      useEventListener('click', (e) => {
          console.log('Clicked!')
      })

  • Real-World Examples

    • Counter Component

      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
      }
    • Todo App

      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
          )
        )
      }
    • Form with Validation

      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()])
    • Debounced Search

      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])


About

React-inspired hooks for reactive state management.

Resources

License

Stars

Watchers

Forks