Constantly throws an error: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
const PlaceOfWork = () => {
const { t } = useTranslation()
const [isAddress] = useState(true)
const accessToken = useSelector(state => state.authUser.accessToken)
const [resApi, setResApi] = useState(null)
const [isLoading, setLoading] = useState(false)
const [isError, setError] = useState(false)
const [isUpdate, setIsUpdate] = useState(false)
const prepareData = (response) => {
//console.log(response?.data?.data)
if(response?.data?.code === 200){
(response?.data?.data) && setResApi(response.data.data);
}
}
useEffect(() => {
requestGetApi(
`user/employee/workplace`,
{ headers: {"X-TOKEN": accessToken} },
prepareData, setLoading, setError
)
}, [isUpdate])
const AddressForm = btnWithModalForm(FormChangeAddress, {
title: !isAddress ? t('pages.personal_data.contacts.button_add_address') :
`${t('pages.personal_data.contacts.title_modal_change_data')}`,
btn_text: !isAddress && t('pages.personal_data.contacts.button_add_address'),
btn_icon: isAddress ? 'PencilAlt' : 'Plus',
btn_type: isAddress ? 'primary' : 'secondary'
}
)
const AddressFormWithApi = withRequestServerApi(AddressForm, 'tool/building/list', { headers: {"X-TOKEN": accessToken} })
const handlerUpdateWorkPlace = () => {
setIsUpdate(true)
}
return (
<>
<Title tag="h3" title ={t('pages.personal_data.contacts.place_work')} classes="mb-2" />
{ isAddress ? (
<>
<InputGroup className="my-1">
<InputGroup.Text>{isLoading ? <MainLoader small/> : <FaMap size="24" />}</InputGroup.Text>
<FormControl disabled value={resApi ? `${resApi.building}, ${resApi.office}` : ''} />
<AddressFormWithApi handlerUpdate={handlerUpdateWorkPlace} />
</InputGroup>
{isUpdate && <AlertMessage status='success'>Данные обновлены</AlertMessage>}
</>
) : <AddressForm />
}
</>
);
};
btnWithModalForm.jsx
import { useState } from 'react';
import { Button, Modal } from "react-bootstrap";
import * as FontAwesome from 'react-icons/fa';
//HOC
//Gets the value ComponentForm
//Return BUTTON and MODAL WINDOW with included ComponentForm
//Adds the modal window closing functionality to the form component
const btnWithModalForm = (ComponentForm, {
title = '', //Title modal window
btn_text = '', //Button text
btn_icon = 'Trash', //Button icon from FONT AWESOME
btn_type = 'secondary', //Type button bootstrap
btn_classes = '', // css style button
modal_size = '', // size modal: sm, md, lg, xl
btn_size = '',
icon_size = 20, // size icon
btn_tooltip= '' // default browser tooltip
}) => {
return function (props) {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const Fa = FontAwesome[`Fa${btn_icon}`];
return (
<>
<Button variant={btn_type} className={`${btn_classes}`} onClick={handleShow} title={btn_tooltip} size={btn_size}>
<Fa size={icon_size}/> {btn_text}
</Button>
<Modal show={show} onHide={handleClose} size={modal_size} centered>
<Modal.Header>
<Modal.Title>{title}</Modal.Title>
</Modal.Header>
<ComponentForm {...props} handleCloseModal={handleClose}/>
</Modal>
</>
)
};
};
export default btnWithModalForm;
withRequestServerApi.jsx
import React, { useState } from 'react';
import axios from "axios";
const SERVER_API = process.env.REACT_APP_SERVER_API;
const withRequestServerApi = (
Component,
apiUrl,
headers = {}
) => {
return function (props) {
const [resApi, setResApi] = useState([])
const [isError, setIsError] = useState(false)
const [errorMessage, setErrorMessage] = useState(null);
const [isLoading, setIsLoading] = useState(false)
const getDataApi = async(prepareData, paramsUrl = '') => {
try {
setIsError(false)
setIsLoading(true)
const response = await axios.get(`${SERVER_API}/${apiUrl}${paramsUrl}`, headers)
// console.log(response);
if (response.status === 200) {
prepareData(response)
} else {
setIsError(true)
}
setIsLoading(false)
} catch (error) {
console.log(error);
setIsError(true)
setIsLoading(false)
}
}
return <Component {...props}
getDataApi={getDataApi}
resApi={resApi}
setResApi={setResApi}
isLoading={isLoading}
setIsLoading={setIsLoading}
isError={isError}
setIsError={setIsError}
errorMessage={errorMessage}
setErrorMessage={setErrorMessage}
/>
}
};
export default withRequestServerApi;
FormChangeAddress.jsx
import React, { useState, useEffect } from 'react';
import { useSelector } from 'react-redux';
import { useTranslation } from "react-i18next";
import "../../../../../i18next";
import { FaBuilding, FaDoorOpen } from 'react-icons/fa';
import { requestGetApi, requestPostApi } from '../../../../../services/api/requestServerApi';
import { Button, Modal, Form, InputGroup } from "react-bootstrap";
import MainLoader from '../../../../../components/Loaders/MainLoader'
import AlertMessage from '../../../../../components/UI/AlertMessage';
const FormChangeAddress = ({
handleCloseModal,
getDataApi,
resApi,
setResApi,
isLoading,
setIsError,
setErrorMessage,
handlerUpdate
}) => {
const { t } = useTranslation();
const [corps, setCorps] = useState(0)
const [room, setRoom] = useState(0)
const accessToken = useSelector(state => state.authUser.accessToken)
const [isSuccessUpdate, setIsSuccessUpdate] = useState(false);
const [isLoadingUpdate, setIsLoadingUpdate] = useState(false);
const [isErrorUpdate, setIsErrorUpdate] = useState(false);
const prepareData = (response) => {
// console.log(response)
if(response?.data?.code === 200){
(Array.isArray(response?.data?.data) && response?.data?.data.length !== 0) && setResApi(response.data.data);
}else{
setIsError(true)
setErrorMessage(response?.data)
}
}
useEffect(() => {
let isMounted = true;
if (isMounted) { getDataApi(prepareData) }
return () => { isMounted = false };
}, [])
const handleSetCorps = (e) => {
setCorps(e.target.value)
}
const handleSetRoom = (e) => {
setRoom(e.target.value)
}
const prepareDataUpdateWorkPlace = (response) => {
console.log(response)
if(response?.data?.code === 200 && response?.data?.data){
setIsSuccessUpdate(true)
handlerUpdate()
}else{
setIsErrorUpdate(true)
}
}
const handleSaveData = () => {
if(room !== 0){
requestPostApi(
'user/employee/workplace',
new URLSearchParams({ room }),
{ headers: {
"X-TOKEN": accessToken,
"Content-Type": "application/x-www-form-urlencoded"
}},
prepareDataUpdateWorkPlace, setIsLoadingUpdate, setIsErrorUpdate
)
}
}
const UpdateWorkPlaceContent = () => {
if(isLoadingUpdate){
return <MainLoader />
}else{
if(!isErrorUpdate && isSuccessUpdate){
return <AlertMessage status='success'>Данные обновлены</AlertMessage>
}
if(isErrorUpdate){
return <AlertMessage status='danger'>Ошибка обновления данных</AlertMessage>
}
}
return null
}
return (
<>
<Modal.Body>
<UpdateWorkPlaceContent/>
{!isSuccessUpdate &&
<>
<SelectOffice defaultVal={corps} resApi={resApi} isLoading={isLoading} onChange={handleSetCorps}/>
<SelectRoom defaultVal={corps} onChange={handleSetRoom}/>
</>
}
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleSaveData}>{t('modal_window.save')}</Button>
<Button variant="secondary" onClick={handleCloseModal}>{t('modal_window.no')}</Button>
</Modal.Footer>
</>
);
};
const SelectOffice = ({defaultVal, resApi, isLoading, onChange}) => {
const { t } = useTranslation();
return (
<>
<label>{t('pages.personal_data.contacts.corps')}</label>
<InputGroup className="mb-4" >
<InputGroup.Text id="basic-addon1">{isLoading ? <MainLoader small style='dark'/> :<FaBuilding/>}</InputGroup.Text>
<Form.Select defaultValue={defaultVal} className="" onChange={onChange}>
<option value={0} disabled>---</option>
{(resApi && resApi.length > 0) && resApi.map(item => (
<option key={item.id} value={item.id}>{item.name}</option>
))}
</Form.Select>
</InputGroup>
</>
)
}
const SelectRoom = ({defaultVal, onChange}) => {
const { t } = useTranslation();
const [resApi, setResApi] = useState([])
const [isLoading, setLoading] = useState(false)
const [isError, setError] = useState(false)
const accessToken = useSelector(state => state.authUser.accessToken)
const prepareData = (response) => {
//console.log(response)
if(response?.data?.code === 200){
(Array.isArray(response?.data?.data) && response?.data?.data.length !== 0) && setResApi(response.data.data);
}
}
useEffect(() => {
defaultVal && requestGetApi(
`tool/building/room?building=${defaultVal}`,
{ headers: {"X-TOKEN": accessToken} },
prepareData, setLoading, setError
)
}, [defaultVal])
return (
<>
<label>{t('pages.personal_data.contacts.placement')}</label>
<InputGroup className="mb-4" >
<InputGroup.Text id="basic-addon1">{isLoading ? <MainLoader small style='dark'/> :<FaDoorOpen/>}</InputGroup.Text>
<Form.Select defaultValue={defaultVal} className="" onChange={onChange} disabled={!!!defaultVal}>
<option value={0} disabled>---</option>
{(resApi && resApi.length > 0) && resApi.map(item => (
<option key={item.id} value={item.id}>{item.name}</option>
))}
</Form.Select>
</InputGroup>
</>
)
}
Does not help
useEffect(() => {
let isMounted = true;
if (isMounted) { getDataApi(prepareData) }
return () => { isMounted = false };
}, [])