@ -1,4 +1,4 @@
import { use State } from "react" ;
import { use Callback, use State } from "react" ;
import type { Attachment } from "@/types/proto/api/v1/attachment_service" ;
import type { Location , MemoRelation } from "@/types/proto/api/v1/memo_service" ;
import { Visibility } from "@/types/proto/api/v1/memo_service" ;
@ -15,6 +15,13 @@ interface MemoEditorState {
isDraggingFile : boolean ;
}
/ * *
* Custom hook for managing MemoEditor state with stable setter references .
*
* Note : All setter functions are wrapped with useCallback to ensure stable references .
* This prevents infinite loops when these setters are used in useEffect dependencies .
* While this makes the code verbose , it ' s necessary for proper React dependency tracking .
* /
export const useMemoEditorState = ( initialVisibility : Visibility = Visibility . PRIVATE ) = > {
const [ state , setState ] = useState < MemoEditorState > ( {
memoVisibility : initialVisibility ,
@ -28,29 +35,66 @@ export const useMemoEditorState = (initialVisibility: Visibility = Visibility.PR
isDraggingFile : false ,
} ) ;
const update = < K extends keyof MemoEditorState > ( key : K , value : MemoEditorState [ K ] ) = > {
setState ( ( prev ) = > ( { . . . prev , [ key ] : value } ) ) ;
} ;
// All setters are memoized with useCallback to provide stable function references.
// This prevents unnecessary re-renders and infinite loops in useEffect hooks.
const setMemoVisibility = useCallback ( ( v : Visibility ) = > {
setState ( ( prev ) = > ( { . . . prev , memoVisibility : v } ) ) ;
} , [ ] ) ;
const setAttachmentList = useCallback ( ( v : Attachment [ ] ) = > {
setState ( ( prev ) = > ( { . . . prev , attachmentList : v } ) ) ;
} , [ ] ) ;
const setRelationList = useCallback ( ( v : MemoRelation [ ] ) = > {
setState ( ( prev ) = > ( { . . . prev , relationList : v } ) ) ;
} , [ ] ) ;
const setLocation = useCallback ( ( v : Location | undefined ) = > {
setState ( ( prev ) = > ( { . . . prev , location : v } ) ) ;
} , [ ] ) ;
const toggleFocusMode = useCallback ( ( ) = > {
setState ( ( prev ) = > ( { . . . prev , isFocusMode : ! prev . isFocusMode } ) ) ;
} , [ ] ) ;
const setUploadingAttachment = useCallback ( ( v : boolean ) = > {
setState ( ( prev ) = > ( { . . . prev , isUploadingAttachment : v } ) ) ;
} , [ ] ) ;
const setRequesting = useCallback ( ( v : boolean ) = > {
setState ( ( prev ) = > ( { . . . prev , isRequesting : v } ) ) ;
} , [ ] ) ;
const setComposing = useCallback ( ( v : boolean ) = > {
setState ( ( prev ) = > ( { . . . prev , isComposing : v } ) ) ;
} , [ ] ) ;
const setDraggingFile = useCallback ( ( v : boolean ) = > {
setState ( ( prev ) = > ( { . . . prev , isDraggingFile : v } ) ) ;
} , [ ] ) ;
const resetState = useCallback ( ( ) = > {
setState ( ( prev ) = > ( {
. . . prev ,
isRequesting : false ,
attachmentList : [ ] ,
relationList : [ ] ,
location : undefined ,
isDraggingFile : false ,
} ) ) ;
} , [ ] ) ;
return {
. . . state ,
setMemoVisibility : ( v : Visibility ) = > update ( "memoVisibility" , v ) ,
setAttachmentList : ( v : Attachment [ ] ) = > update ( "attachmentList" , v ) ,
setRelationList : ( v : MemoRelation [ ] ) = > update ( "relationList" , v ) ,
setLocation : ( v : Location | undefined ) = > update ( "location" , v ) ,
toggleFocusMode : ( ) = > setState ( ( prev ) = > ( { . . . prev , isFocusMode : ! prev . isFocusMode } ) ) ,
setUploadingAttachment : ( v : boolean ) = > update ( "isUploadingAttachment" , v ) ,
setRequesting : ( v : boolean ) = > update ( "isRequesting" , v ) ,
setComposing : ( v : boolean ) = > update ( "isComposing" , v ) ,
setDraggingFile : ( v : boolean ) = > update ( "isDraggingFile" , v ) ,
resetState : ( ) = >
setState ( ( prev ) = > ( {
. . . prev ,
isRequesting : false ,
attachmentList : [ ] ,
relationList : [ ] ,
location : undefined ,
isDraggingFile : false ,
} ) ) ,
setMemoVisibility ,
setAttachmentList ,
setRelationList ,
setLocation ,
toggleFocusMode ,
setUploadingAttachment ,
setRequesting ,
setComposing ,
setDraggingFile ,
resetState ,
} ;
} ;