'How to use useEffect properly to validate wether mounted or not mounted yet?

I have problem regarding Warning: Can't perform a React state update on an unmounted component. Every time I press and select on my select option I always get this yellow warning prompt on my mobile screen.

I read some articles that this error found on my useEffect but I don't know how to trace this error warning inside on my useEffect. Can you help me guys to solve this kind of problem?

Here is what I have on my codes:

const mountedRef = true;

const HandleGetRegion = () => {
    dispatch(RegionList()).then((response) => {
        if(mountedRef) setRegionList(response?.payload)
    });
}

const HandleGetProvince =  (id) => {
    dispatch(ProvinceList(id)).then((response) => {
        if(mountedRef) setProvinceList(response?.payload)
    });
}

const HandleGetCity =  (id) => {
        dispatch(CityList(id)).then((response) => {
            if(mountedRef) setCityList(response?.payload)
        });
    }



useEffect(() => {
    HandleGetRegion();
    HandleGetProvince();
    HandleGetCity();
    return () => {
        mountedRef.current = false;
    }
}, [])

Here is what my selection look like

<View style={{ flexDirection: 'row', flex: 1, flexWrap: 'wrap', alignItems: 'flex-start' }}>
<View style={{ width: '50%', padding: 3 }}>
    <Text style={{ fontSize: 12, marginTop: 10 }}>Region</Text>
    <Select
        accessibilityLabel="Region"
        placeholder="Region"
        placeholderTextColor="#000"
        color="#000"
        mt={1}
        name="pickup_region"
        selectedValue={values.pickup_region}
        onBlur={handleBlur('pickup_region')}
        onValueChange={(itemValue) => {
            setFieldValue("pickup_region", itemValue);
            HandleGetProvince(itemValue);
        }}

    >
        {
            regionList && regionList?.data ? (
                regionList.data?.map((data, i) => {
                    return (

                        <Select.Item key={i} label={data.name} value={data.id.toString()} />

                    )
                })
            ) : <Select.Item label="No Region Available" value="" />
        }
    </Select>
    {(errors.pickup_region && touched.pickup_region) &&
        <Text style={styles.errorText}>{errors.pickup_region}</Text>
    }
</View>
<View style={{ width: '50%', padding: 3 }}>
    <Text style={{ fontSize: 12, marginTop: 10 }}>Province</Text>
    <Select
        accessibilityLabel="Province"
        placeholder="Province"
        placeholderTextColor="#000"
        color="#000"
        mt={1}
        selectedValue={values.pickup_province}
        onBlur={handleBlur('pickup_province')}
        name="pickup_province"
        onValueChange={(itemValue) => {
            setFieldValue("pickup_province", itemValue);
            HandleGetCity(itemValue);
        }}
    >
        {
            provinceList && provinceList?.data ? (
                provinceList.data?.map((data, i) => {
                    return (

                        <Select.Item key={i} label={data.name} value={data.id.toString()} />

                    )
                })
            ) : <Select.Item label="No Provinces Available" value="" />
        }
    </Select>
    {(errors.pickup_province && touched.pickup_province) &&
        <Text style={styles.errorText}>{errors.pickup_province}</Text>
    }
</View>

Error:

Error Prompt



Solution 1:[1]

While it has been planning to remove from warnings entirely, I am seeing that you are initializing mountedRef with const which is not correct.

Usually such typical flow should be the following checking whether if component is mounted,

// Create a custom hook so that you avoid repetition

import { useCallback, useEffect, useRef } from 'react'

function useIsMounted() {
  const isMounted = useRef(false)

  useEffect(() => {
    isMounted.current = true

    return () => {
      isMounted.current = false
    }
  }, [])

  return useCallback(() => isMounted.current, [])
}

export default useIsMounted
// Usage of hook

function Child() {
  const [data, setData] = useState('loading')
  const isMounted = useIsMounted()

  // simulate an api call and update state
  useEffect(() => {
    yourApiCall().then((data) => {
      if (isMounted()) setData(data)
    })
  }, [isMounted])

  return <p>{data}</p>
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tarik