@startsimpli/hooks 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@startsimpli/hooks",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Shared React hooks for StartSimpli apps",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, useCallback } from 'react'
1
+ import { useState, useEffect, useCallback, useRef } from 'react'
2
2
 
3
3
  export interface SavedView {
4
4
  id: string
@@ -37,10 +37,20 @@ export function useSavedViews<T extends SavedView>({
37
37
  error: null,
38
38
  })
39
39
 
40
+ // Store callbacks in refs to avoid infinite loops when callers pass inline functions
41
+ const loadFnRef = useRef(loadFn)
42
+ const saveFnRef = useRef(saveFn)
43
+ const updateFnRef = useRef(updateFn)
44
+ const deleteFnRef = useRef(deleteFn)
45
+ loadFnRef.current = loadFn
46
+ saveFnRef.current = saveFn
47
+ updateFnRef.current = updateFn
48
+ deleteFnRef.current = deleteFn
49
+
40
50
  const fetchViews = useCallback(async () => {
41
51
  setState(prev => ({ ...prev, loading: true, error: null }))
42
52
  try {
43
- const views = await loadFn(resource)
53
+ const views = await loadFnRef.current(resource)
44
54
  const defaultView = views.find(v => v.isDefault)
45
55
  setState(prev => ({
46
56
  ...prev,
@@ -55,7 +65,7 @@ export function useSavedViews<T extends SavedView>({
55
65
  error: error instanceof Error ? error.message : 'Failed to load views',
56
66
  }))
57
67
  }
58
- }, [resource, loadFn])
68
+ }, [resource])
59
69
 
60
70
  useEffect(() => {
61
71
  fetchViews()
@@ -63,7 +73,7 @@ export function useSavedViews<T extends SavedView>({
63
73
 
64
74
  const saveView = useCallback(
65
75
  async (viewData: Omit<T, 'id' | 'createdAt'>): Promise<T> => {
66
- const newView = await saveFn(resource, viewData)
76
+ const newView = await saveFnRef.current(resource, viewData)
67
77
  setState(prev => ({
68
78
  ...prev,
69
79
  views: [...prev.views, newView],
@@ -71,27 +81,27 @@ export function useSavedViews<T extends SavedView>({
71
81
  }))
72
82
  return newView
73
83
  },
74
- [resource, saveFn]
84
+ [resource]
75
85
  )
76
86
 
77
87
  const updateView = useCallback(
78
88
  async (viewId: string, updates: Partial<T>): Promise<void> => {
79
- await updateFn(resource, viewId, updates)
89
+ await updateFnRef.current(resource, viewId, updates)
80
90
  await fetchViews()
81
91
  },
82
- [resource, updateFn, fetchViews]
92
+ [resource, fetchViews]
83
93
  )
84
94
 
85
95
  const deleteView = useCallback(
86
96
  async (viewId: string): Promise<void> => {
87
- await deleteFn(resource, viewId)
97
+ await deleteFnRef.current(resource, viewId)
88
98
  setState(prev => ({
89
99
  ...prev,
90
100
  views: prev.views.filter(v => v.id !== viewId),
91
101
  currentViewId: prev.currentViewId === viewId ? null : prev.currentViewId,
92
102
  }))
93
103
  },
94
- [resource, deleteFn]
104
+ [resource]
95
105
  )
96
106
 
97
107
  const loadView = useCallback((viewId: string) => {