diff --git a/.changeset/flat-state-hook-returns.md b/.changeset/flat-state-hook-returns.md
new file mode 100644
index 00000000..ce8e2788
--- /dev/null
+++ b/.changeset/flat-state-hook-returns.md
@@ -0,0 +1,5 @@
+---
+'react-simplikit': major
+---
+
+Return a single object from `useBooleanState`, `useStorageState`, `useList`, `useMap`, and `useSet`. State values and actions are now named fields.
diff --git a/packages/plugin/skills/react-simplikit/references/useBooleanState.md b/packages/plugin/skills/react-simplikit/references/useBooleanState.md
index 3ef27c3e..845af31a 100644
--- a/packages/plugin/skills/react-simplikit/references/useBooleanState.md
+++ b/packages/plugin/skills/react-simplikit/references/useBooleanState.md
@@ -6,14 +6,12 @@ It provides functions to set the state to `true`, set it to `false`, and toggle
## Interface
```ts
-function useBooleanState(
- initialValue: boolean | (() => boolean) = false
-): readonly [
- state: boolean,
- setTrue: () => void,
- setFalse: () => void,
- toggle: () => void,
-];
+function useBooleanState(initialValue: boolean | (() => boolean) = false): {
+ value: boolean;
+ setTrue: () => void;
+ setFalse: () => void;
+ toggle: () => void;
+};
```
### Parameters
@@ -28,11 +26,11 @@ function useBooleanState(
## Example
```tsx
-const [userMap, actions] = useMap([
+const { map: userMap, set } = useMap([
['user1', { name: 'John', age: 30 }],
]);
@@ -37,5 +37,5 @@ const [userMap, actions] = useMap([
const user1 = userMap.get('user1');
// Updating the Map
-actions.set('user2', { name: 'Jane', age: 25 });
+set('user2', { name: 'Jane', age: 25 });
```
diff --git a/packages/plugin/skills/react-simplikit/references/useSet.md b/packages/plugin/skills/react-simplikit/references/useSet.md
index 3701fbba..58b45e29 100644
--- a/packages/plugin/skills/react-simplikit/references/useSet.md
+++ b/packages/plugin/skills/react-simplikit/references/useSet.md
@@ -22,40 +22,40 @@ function useSet(initialState: SetOrValues = new Set()): UseSetReturn;
@@ -94,9 +90,12 @@ function useStorageState(
import { useStorageState } from 'react-simplikit';
function Counter() {
- const [count, setCount] = useStorageState('counter', {
- defaultValue: 0,
- });
+ const { value: count, setValue: setCount } = useStorageState(
+ 'counter',
+ {
+ defaultValue: 0,
+ }
+ );
return (
diff --git a/packages/react-simplikit/src/hooks/useBooleanState/es/useBooleanState.md b/packages/react-simplikit/src/hooks/useBooleanState/es/useBooleanState.md
index 4cd9664c..93989b7e 100644
--- a/packages/react-simplikit/src/hooks/useBooleanState/es/useBooleanState.md
+++ b/packages/react-simplikit/src/hooks/useBooleanState/es/useBooleanState.md
@@ -6,14 +6,12 @@ Proporciona funciones para establecer el estado en `true`, establecerlo en `fals
## Interfaz
```ts
-function useBooleanState(
- initialValue: boolean | (() => boolean) = false
-): readonly [
- state: boolean,
- setTrue: () => void,
- setFalse: () => void,
- toggle: () => void,
-];
+function useBooleanState(initialValue: boolean | (() => boolean) = false): {
+ value: boolean;
+ setTrue: () => void;
+ setFalse: () => void;
+ toggle: () => void;
+};
```
### Parámetros
@@ -28,11 +26,11 @@ function useBooleanState(
## Ejemplo
```tsx
-const [userMap, actions] = useMap([
+const { map: userMap, set } = useMap([
['user1', { name: 'John', age: 30 }],
]);
@@ -37,5 +37,5 @@ const [userMap, actions] = useMap([
const user1 = userMap.get('user1');
// Actualizar el Map
-actions.set('user2', { name: 'Jane', age: 25 });
+set('user2', { name: 'Jane', age: 25 });
```
diff --git a/packages/react-simplikit/src/hooks/useMap/ja/useMap.md b/packages/react-simplikit/src/hooks/useMap/ja/useMap.md
index 15f0fe65..1856d161 100644
--- a/packages/react-simplikit/src/hooks/useMap/ja/useMap.md
+++ b/packages/react-simplikit/src/hooks/useMap/ja/useMap.md
@@ -23,13 +23,13 @@ function useMap(initialState: MapOrEntries): UseMapReturn;
## 使用例
```tsx
-const [userMap, actions] = useMap([
+const { map: userMap, set } = useMap([
['user1', { name: 'John', age: 30 }],
]);
@@ -37,5 +37,5 @@ const [userMap, actions] = useMap([
const user1 = userMap.get('user1');
// Map を更新します
-actions.set('user2', { name: 'Jane', age: 25 });
+set('user2', { name: 'Jane', age: 25 });
```
diff --git a/packages/react-simplikit/src/hooks/useMap/ko/useMap.md b/packages/react-simplikit/src/hooks/useMap/ko/useMap.md
index 0c0ab92e..2d9f138b 100644
--- a/packages/react-simplikit/src/hooks/useMap/ko/useMap.md
+++ b/packages/react-simplikit/src/hooks/useMap/ko/useMap.md
@@ -22,13 +22,13 @@ function useMap(initialState: MapOrEntries): UseMapReturn;
## 예시
```tsx
-const [userMap, actions] = useMap([
+const { map: userMap, set } = useMap([
['user1', { name: 'John', age: 30 }],
]);
@@ -36,5 +36,5 @@ const [userMap, actions] = useMap([
const user1 = userMap.get('user1');
// 맵 업데이트하기
-actions.set('user2', { name: 'Jane', age: 25 });
+set('user2', { name: 'Jane', age: 25 });
```
diff --git a/packages/react-simplikit/src/hooks/useMap/useMap.md b/packages/react-simplikit/src/hooks/useMap/useMap.md
index ab50cf3d..f2625d07 100644
--- a/packages/react-simplikit/src/hooks/useMap/useMap.md
+++ b/packages/react-simplikit/src/hooks/useMap/useMap.md
@@ -23,13 +23,13 @@ function useMap(initialState: MapOrEntries): UseMapReturn;
## Example
```tsx
-const [userMap, actions] = useMap([
+const { map: userMap, set } = useMap([
['user1', { name: 'John', age: 30 }],
]);
@@ -37,5 +37,5 @@ const [userMap, actions] = useMap([
const user1 = userMap.get('user1');
// Updating the Map
-actions.set('user2', { name: 'Jane', age: 25 });
+set('user2', { name: 'Jane', age: 25 });
```
diff --git a/packages/react-simplikit/src/hooks/useMap/useMap.spec.ts b/packages/react-simplikit/src/hooks/useMap/useMap.spec.ts
index eaf9dd72..d948758b 100644
--- a/packages/react-simplikit/src/hooks/useMap/useMap.spec.ts
+++ b/packages/react-simplikit/src/hooks/useMap/useMap.spec.ts
@@ -10,46 +10,46 @@ describe('useMap', () => {
const initialMap = new Map([[1, 'initial']]);
const { result } = await renderHookSSR(() => useMap(initialMap));
- expect(result.current[0].get(1)).toBe('initial');
+ expect(result.current.map.get(1)).toBe('initial');
});
it('should initialize with an array of entries', async () => {
const { result } = await renderHookSSR(() => useMap([[1, 'initial']]));
- expect(result.current[0].get(1)).toBe('initial');
+ expect(result.current.map.get(1)).toBe('initial');
});
it('should initialize with an empty Map when no arguments provided', async () => {
const { result } = await renderHookSSR(() => useMap());
- expect(result.current[0].size).toBe(0);
+ expect(result.current.map.size).toBe(0);
});
it('should add a new value to the Map', async () => {
const { result, rerender } = await renderHookSSR(() => useMap());
- const [, actions] = result.current;
+ const actions = result.current;
- expect(result.current[0].get(1)).toBeUndefined();
+ expect(result.current.map.get(1)).toBeUndefined();
await act(async () => {
actions.set(1, 'added');
rerender();
});
- expect(result.current[0].get(1)).toBe('added');
+ expect(result.current.map.get(1)).toBe('added');
});
it('should update an existing value in the Map', async () => {
const initialMap = new Map([[1, 'initial']]);
const { result, rerender } = await renderHookSSR(() => useMap(initialMap));
- const [, actions] = result.current;
+ const actions = result.current;
await act(async () => {
actions.set(1, 'edited');
rerender();
});
- expect(result.current[0].get(1)).toBe('edited');
+ expect(result.current.map.get(1)).toBe('edited');
});
it('should replace all values with setAll', async () => {
@@ -58,40 +58,40 @@ describe('useMap', () => {
[2, 'example'],
]);
const { result, rerender } = await renderHookSSR(() => useMap(initialMap));
- const [, actions] = result.current;
+ const actions = result.current;
- expect(result.current[0].get(1)).toBe('initial');
- expect(result.current[0].get(2)).toBe('example');
- expect(result.current[0].size).toBe(2);
+ expect(result.current.map.get(1)).toBe('initial');
+ expect(result.current.map.get(2)).toBe('example');
+ expect(result.current.map.size).toBe(2);
await act(async () => {
actions.setAll([[1, 'edited']]);
rerender();
});
- expect(result.current[0].get(1)).toBe('edited');
- expect(result.current[0].get(2)).toBeUndefined();
- expect(result.current[0].size).toBe(1);
+ expect(result.current.map.get(1)).toBe('edited');
+ expect(result.current.map.get(2)).toBeUndefined();
+ expect(result.current.map.size).toBe(1);
});
it('should remove an existing value from the Map', async () => {
const initialMap = new Map([[1, 'initial']]);
const { result, rerender } = await renderHookSSR(() => useMap(initialMap));
- const [, actions] = result.current;
+ const actions = result.current;
await act(async () => {
actions.remove(1);
rerender();
});
- expect(result.current[0].get(1)).toBeUndefined();
- expect(result.current[0].size).toBe(0);
+ expect(result.current.map.get(1)).toBeUndefined();
+ expect(result.current.map.size).toBe(0);
});
it('should reset the Map to its initial state', async () => {
const initialMap = new Map([[1, 'initial']]);
const { result, rerender } = await renderHookSSR(() => useMap(initialMap));
- const [, actions] = result.current;
+ const actions = result.current;
// First modify the map
await act(async () => {
@@ -100,9 +100,9 @@ describe('useMap', () => {
rerender();
});
- expect(result.current[0].get(1)).toBe('modified');
- expect(result.current[0].get(2)).toBe('added');
- expect(result.current[0].size).toBe(2);
+ expect(result.current.map.get(1)).toBe('modified');
+ expect(result.current.map.get(2)).toBe('added');
+ expect(result.current.map.size).toBe(2);
// Then reset to initial state
await act(async () => {
@@ -111,14 +111,14 @@ describe('useMap', () => {
});
// Should be back to initial state
- expect(result.current[0].get(1)).toBe('initial');
- expect(result.current[0].get(2)).toBeUndefined();
- expect(result.current[0].size).toBe(1);
+ expect(result.current.map.get(1)).toBe('initial');
+ expect(result.current.map.get(2)).toBeUndefined();
+ expect(result.current.map.size).toBe(1);
});
it('should reset to empty Map when initialized with empty Map', async () => {
const { result, rerender } = await renderHookSSR(() => useMap());
- const [, actions] = result.current;
+ const actions = result.current;
// Add some items
await act(async () => {
@@ -127,7 +127,7 @@ describe('useMap', () => {
rerender();
});
- expect(result.current[0].size).toBe(2);
+ expect(result.current.map.size).toBe(2);
// Reset should restore to empty state
await act(async () => {
@@ -135,37 +135,37 @@ describe('useMap', () => {
rerender();
});
- expect(result.current[0].size).toBe(0);
+ expect(result.current.map.size).toBe(0);
});
it('should create a new Map reference when values change', async () => {
const initialMap = new Map();
const { result, rerender } = await renderHookSSR(() => useMap(initialMap));
- const [originalMapRef, actions] = result.current;
+ const { map: originalMapRef, set } = result.current;
await act(async () => {
- actions.set(1, 1);
+ set(1, 1);
rerender();
});
- expect(originalMapRef).not.toBe(result.current[0]);
+ expect(originalMapRef).not.toBe(result.current.map);
expect(originalMapRef.get(1)).toBeUndefined();
- expect(result.current[0].get(1)).toBe(1);
+ expect(result.current.map.get(1)).toBe(1);
});
it('should maintain stable actions reference after Map changes', async () => {
const initialMap = new Map();
const { result, rerender } = await renderHookSSR(() => useMap(initialMap));
- const [, originalActionsRef] = result.current;
+ const originalActionsRef = result.current;
- expect(result.current[1]).toBe(originalActionsRef);
+ expect(result.current.set).toBe(originalActionsRef.set);
await act(async () => {
originalActionsRef.set(1, 1);
rerender();
});
- expect(result.current[1]).toBe(originalActionsRef);
+ expect(result.current.set).toBe(originalActionsRef.set);
});
it('is safe in server-side rendering', () => {
diff --git a/packages/react-simplikit/src/hooks/useMap/useMap.ts b/packages/react-simplikit/src/hooks/useMap/useMap.ts
index 1e60a994..03d36d3b 100644
--- a/packages/react-simplikit/src/hooks/useMap/useMap.ts
+++ b/packages/react-simplikit/src/hooks/useMap/useMap.ts
@@ -1,4 +1,4 @@
-import { useCallback, useMemo, useState } from 'react';
+import { useCallback, useState } from 'react';
import { usePreservedReference } from '../usePreservedReference/usePreservedReference.ts';
@@ -25,7 +25,7 @@ type MapActions = {
* Return type of the useMap hook.
* Hides certain methods to prevent direct mutations.
*/
-type UseMapReturn = [Omit