1
- import React , { useEffect , useState } from 'react' ;
1
+ import React , { useEffect , useState , useRef } from 'react' ;
2
2
import { isEmpty } from "lodash" ;
3
3
import Image from '../image' ;
4
4
import { deleteCartItem , updateCart } from '../../utils/cart' ;
@@ -14,6 +14,29 @@ const CartItem = ( {
14
14
const [ removingProduct , setRemovingProduct ] = useState ( false ) ;
15
15
const productImg = item ?. data ?. images ?. [ 0 ] ?? '' ;
16
16
17
+ /**
18
+ * isMounted is used so that we can set it's value to false
19
+ * when the component is unmounted.
20
+ * This is done so that setState ( e.g setRemovingProduct ) in asynchronous calls
21
+ * such as axios.post, do not get executed when component leaves the DOM
22
+ * due to product/item deletion.
23
+ * If we do not do this as unsubscription, we will get
24
+ * "React memory leak warning- Can't perform a React state update on an unmounted component"
25
+ *
26
+ * @see https://dev.to/jexperton/how-to-fix-the-react-memory-leak-warning-d4i
27
+ * @type {React.MutableRefObject<boolean> }
28
+ */
29
+ const isMounted = useRef ( false ) ;
30
+
31
+ useEffect ( ( ) => {
32
+ isMounted . current = true
33
+
34
+ // When component is unmounted, set isMounted.current to false.
35
+ return ( ) => {
36
+ isMounted . current = false
37
+ }
38
+ } , [ ] )
39
+
17
40
/*
18
41
* Handle remove product click.
19
42
*
@@ -25,9 +48,12 @@ const CartItem = ( {
25
48
const handleRemoveProductClick = ( event , cartKey ) => {
26
49
event . stopPropagation ( ) ;
27
50
28
- if ( ! updatingProduct ) {
29
- deleteCartItem ( cartKey , setCart , setRemovingProduct ) ;
51
+ // If the component is unmounted, or still previous item update request is in process, then return.
52
+ if ( ! isMounted || updatingProduct ) {
53
+ return ;
30
54
}
55
+
56
+ deleteCartItem ( cartKey , setCart , setRemovingProduct ) ;
31
57
} ;
32
58
33
59
/*
0 commit comments