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()
}, [])