create()

Combines a model and its actions into a React hook.

import { create } from 'comwit'

Usage

import { create } from 'comwit'
import type { PostState, PostActions } from './types'
import { post } from './model'
import { crudActions } from './actions/crud'
import { loadActions } from './actions/load'

export const usePost = create<PostState, PostActions>(post, {
  actions: [crudActions, loadActions],
})

Selector pattern

The returned hook accepts an optional selector:

// Select specific fields — only re-renders when these change
const { posts, actions } = usePost((s) => ({
  posts: s.posts,
  actions: s.actions,
}))

// No selector — returns everything (re-renders on any change)
const state = usePost()

Deep equality

Selectors use deep equality comparison. The component only re-renders when the selected values actually change, not on every state mutation.

// This only re-renders when posts.data changes, not when
// unrelated state like `current` changes
const { posts } = usePost((s) => ({ posts: s.posts }))

Reading query fields

Query fields expose data and status flags:

const { posts, actions } = usePost((s) => ({
  posts: s.posts,
  actions: s.actions,
}))

if (posts.isLoading) return <Skeleton />
if (posts.isError) return <p>Error: {posts.error}</p>
return posts.data.map((post) => <Card key={post.id} post={post} />)

Calling actions

Actions are available on s.actions:

const { actions } = usePost((s) => ({ actions: s.actions }))

useEffect(() => {
  actions.loadPosts()
}, [])