@@ -46,6 +46,7 @@ export interface CellProps {
4646 cellTooltip ?: string ;
4747 editMode ?: string ;
4848 onTableEvent ?: ( eventName : any ) => void ;
49+ cellIndex ?: string ;
4950}
5051
5152export type CellViewReturn = ( props : CellProps ) => ReactNode ;
@@ -65,7 +66,7 @@ const BorderDiv = styled.div`
6566 left: 0;
6667` ;
6768
68- const CellWrapper = ( {
69+ const CellWrapper = React . memo ( ( {
6970 children,
7071 tooltipTitle,
7172} : {
@@ -82,7 +83,7 @@ const CellWrapper = ({
8283 return (
8384 < > { children } </ >
8485 )
85- } ;
86+ } ) ;
8687
8788interface EditableCellProps < T > extends CellProps {
8889 normalView : ReactNode ;
@@ -108,6 +109,7 @@ function EditableCellComp<T extends JSONValue>(props: EditableCellProps<T>) {
108109 tableSize,
109110 textOverflow,
110111 cellTooltip,
112+ cellIndex,
111113 ...otherProps
112114 } = props ;
113115
@@ -118,15 +120,23 @@ function EditableCellComp<T extends JSONValue>(props: EditableCellProps<T>) {
118120 const [ tmpValue , setTmpValue ] = useState < T | null > ( value ) ;
119121 const singleClickEdit = editMode === 'single' ;
120122
121- // Use refs to track previous values for comparison
123+ // Use refs to track component mount state and previous values
124+ const mountedRef = useRef ( true ) ;
122125 const prevValueRef = useRef ( value ) ;
123126
127+ // Cleanup on unmount
124128 useEffect ( ( ) => {
125- console . log ( "rendered EditableCellComp" ) ;
126- } , [ ] ) ;
129+ return ( ) => {
130+ mountedRef . current = false ;
131+ setTmpValue ( null ) ;
132+ setIsEditing ( false ) ;
133+ } ;
134+ } , [ setIsEditing ] ) ;
127135
128136 // Update tmpValue when value changes
129137 useEffect ( ( ) => {
138+ if ( ! mountedRef . current ) return ;
139+
130140 if ( ! _ . isEqual ( value , prevValueRef . current ) ) {
131141 setTmpValue ( value ) ;
132142 prevValueRef . current = value ;
@@ -135,12 +145,15 @@ function EditableCellComp<T extends JSONValue>(props: EditableCellProps<T>) {
135145
136146 const onChange = useCallback (
137147 ( value : T ) => {
148+ if ( ! mountedRef . current ) return ;
138149 setTmpValue ( value ) ;
139150 } ,
140151 [ ]
141152 ) ;
142153
143154 const onChangeEnd = useCallback ( ( ) => {
155+ if ( ! mountedRef . current ) return ;
156+
144157 setIsEditing ( false ) ;
145158 const newValue = _ . isNil ( tmpValue ) || _ . isEqual ( tmpValue , baseValue ) ? null : tmpValue ;
146159 dispatch (
@@ -153,32 +166,28 @@ function EditableCellComp<T extends JSONValue>(props: EditableCellProps<T>) {
153166 if ( ! _ . isEqual ( tmpValue , value ) ) {
154167 onTableEvent ?.( 'columnEdited' ) ;
155168 }
156- } , [ dispatch , tmpValue , baseValue , value , onTableEvent ] ) ;
169+ } , [ dispatch , tmpValue , baseValue , value , onTableEvent , setIsEditing ] ) ;
157170
158171 const editView = useMemo (
159172 ( ) => editViewFn ?.( { value, onChange, onChangeEnd, otherProps } ) ?? < > </ > ,
160173 [ editViewFn , value , onChange , onChangeEnd , otherProps ]
161174 ) ;
162175
163176 const enterEditFn = useCallback ( ( ) => {
164- if ( editable ) setIsEditing ( true ) ;
177+ if ( ! mountedRef . current || ! editable ) return ;
178+ setIsEditing ( true ) ;
165179 } , [ editable , setIsEditing ] ) ;
166180
167- // Cleanup function
168- useEffect ( ( ) => {
169- return ( ) => {
170- // Reset state on unmount
171- setTmpValue ( null ) ;
172- setIsEditing ( false ) ;
173- } ;
174- } , [ setIsEditing ] ) ;
175-
181+ // Memoize context values to prevent unnecessary re-renders
182+ const tagsContextValue = useMemo ( ( ) => candidateTags ?? [ ] , [ candidateTags ] ) ;
183+ const statusContextValue = useMemo ( ( ) => candidateStatus ?? [ ] , [ candidateStatus ] ) ;
184+
176185 if ( isEditing ) {
177186 return (
178187 < >
179188 < BorderDiv className = "editing-border" />
180- < TagsContext . Provider value = { candidateTags ?? [ ] } >
181- < StatusContext . Provider value = { candidateStatus ?? [ ] } >
189+ < TagsContext . Provider value = { tagsContextValue } >
190+ < StatusContext . Provider value = { statusContextValue } >
182191 < div className = "editing-wrapper" >
183192 { editView }
184193 </ div >
@@ -189,30 +198,30 @@ function EditableCellComp<T extends JSONValue>(props: EditableCellProps<T>) {
189198 }
190199
191200 return (
192- < ColumnTypeView
193- textOverflow = { props . textOverflow }
194- >
195- { status === "toSave" && ! isEditing && < EditableChip key = { `editable-chip` } /> }
201+ < ColumnTypeView
202+ textOverflow = { props . textOverflow }
203+ >
204+ { status === "toSave" && ! isEditing && < EditableChip key = { `editable-chip-${ cellIndex } ` } /> }
205+ < CellWrapper tooltipTitle = { props . cellTooltip } >
206+ < div
207+ key = { `normal-view-${ cellIndex } ` }
208+ tabIndex = { editable ? 0 : - 1 }
209+ onFocus = { enterEditFn }
210+ >
211+ { normalView }
212+ </ div >
213+ </ CellWrapper >
214+ { /* overlay on normal view to handle double click for editing */ }
215+ { editable && (
196216 < CellWrapper tooltipTitle = { props . cellTooltip } >
197- < div
198- key = { `normal-view` }
199- tabIndex = { editable ? 0 : - 1 }
200- onFocus = { enterEditFn }
201- >
202- { normalView }
203- </ div >
204- </ CellWrapper >
205- { /* overlay on normal view to handle double click for editing */ }
206- { editable && (
207- < CellWrapper tooltipTitle = { props . cellTooltip } >
208217 < EditableOverlay
209- key = " editable-view"
218+ key = { ` editable-view- ${ cellIndex } ` }
210219 onDoubleClick = { ! singleClickEdit ? enterEditFn : undefined }
211220 onClick = { singleClickEdit ? enterEditFn : undefined }
212221 />
213222 </ CellWrapper >
214- ) }
215- </ ColumnTypeView >
223+ ) }
224+ </ ColumnTypeView >
216225 ) ;
217226}
218227
0 commit comments