0

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 };
    }, [])

0 Answers0