useObjectState
State & dataObject state with immutable partial updates (patch/merge) and reset
Install
$ npm install @usefy/use-object-stateQuick start
useObjectState.tsx
import { useObjectState } from "@usefy/use-object-state";
interface FormState {
name: string;
email: string;
subscribe: boolean;
}
function SignupForm() {
const [form, patch, reset] = useObjectState<FormState>({
name: "",
email: "",
subscribe: false,
});
return (
<form>
<input
value={form.name}
onChange={(e) => patch({ name: e.target.value })}
/>
<input
value={form.email}
onChange={(e) => patch({ email: e.target.value })}
/>
<label>
<input
type="checkbox"
checked={form.subscribe}
onChange={(e) => patch({ subscribe: e.target.checked })}
/>
Subscribe
</label>
<button type="button" onClick={() => reset()}>
Reset
</button>
</form>
);
}API reference
useObjectState<T extends object>(initialState)
Returns a [state, patch, reset] tuple.
Parameters
| Parameter | Type | Description |
|---|---|---|
initialState | T | (() => T) | The initial object, or a factory returning it (evaluated once on mount, then cached) |
T must be a plain object/record — this hook is for objects, not arrays (use useList) or primitives (use useState).
Returns [state, patch, reset]
| Item | Type | Description |
|---|---|---|
state | T | The current object |
patch | ObjectStatePatch<T> | Immutably shallow-merge a Partial<T> (or a functional updater) |
reset | ObjectStateReset<T> | Restore the initial value, or set a provided object |
patch(partial | updater)
patch({ field: newValue }); // shallow-merge a partial
patch((prev) => ({ count: prev.count + 1 })); // compute the patch from prev
- Accepts a
Partial<T>and shallow-merges it immutably:{ ...prev, ...partial }. It always produces a new object; the previous state is never mutated. - Also accepts a functional updater
(prev: T) => Partial<T>for when the next value depends on the current one. - Only the provided keys change; untouched keys are preserved by reference.
- Every
patchtriggers a re-render — there is no shallow-equality dedupe (matchingreact-use'suseSetState). This keeps the semantics simple and predictable; add your own guard if you need to skip no-ops.
reset(next?)
reset(); // back to the initial state captured on mount
reset(nextState); // set to the provided object instead
reset()restores the value captured on mount. If a lazy initializer was used, the value it produced is cached once and reused — the initializer is not re-run.reset(nextState)replaces the state with the provided object.
Shallow-merge caveat
The merge is shallow — a nested object in the patch replaces the previous nested object wholesale, it is not deep-merged:
const [state, patch] = useObjectState({ user: { name: "Alice", age: 30 } });
patch({ user: { name: "Bob" } });
// state.user is now { name: "Bob" } — `age` is gone.
// Spread the nested object yourself to update one nested field:
patch({ user: { ...state.user, name: "Bob" } });
Types
import {
useObjectState,
type ObjectStateInitializer,
type ObjectStatePatch,
type ObjectStateReset,
type UseObjectStateReturn,
} from "@usefy/use-object-state";
Go deeper
This page is the quick reference. For every example, prop, and edge case, read the full README — or open Storybook to change props live.