簡體   English   中英

React 警告:無法對卸載的組件執行 React 狀態更新。 要修復,請取消所有訂閱

[英]React Warning: Can't perform a React state update on an unmounted component. To fix, cancel all subscriptions

嘗試更改模態內的值時收到上述警告:

我有一個彈出窗口,當我更改模式中國家/地區代碼字段的值時,一切正常。 但是一旦我保存或關閉模態,狀態變量的值就變得未定義。

主模態文件:

const EditDetailsModal = props => {
    const dispatch = useDispatch()
    const intl = useIntl()
    const shouldShowModal = useSelector(selectors.shouldShowEditDetailsModal)
  const name = useSelector(selectors.getName)
  const email = useSelector(selectors.getEmail)
    const phoneNumber = useSelector(selectors.getPhone)
    const country = useSelector(selectors.getCountry)
  const phoneCode = useSelector(selectors.getPhoneCountryCode)
    const [newName, setNewName] = React.useState(name)
    const [newEmail, setNewEmail] = React.useState(email)
    const [newPhone, setNewPhone] = React.useState(phoneNumber)
  const [newPhoneCode, setNewPhoneCode] = React.useState(phoneCode)
    
    const _handleOnModalHide = React.useCallback(() => {
    setNewEmail(email)
    setNewName(name)
    setNewPhone(phoneNumber)
    setNewCountry(country)
    setRequestPhoneValue(phoneNumber)
        dispatch(actions.hideEditDetailsModal())
    }, [dispatch, name, setNewName, email, newEmail, setNewEmail, phoneNumber, setNewPhone, country, setNewCountry, setRequestPhoneValue ])

  const _phoneCountryCodeChangeCallback = React.useCallback((code) => {
    setNewPhoneCode(code)
  },[setNewPhoneCode])

    const _handleSaveBtnClick = React.useCallback(() => {
        if (isSaveBtnActive) {
            dispatch(actions.startRequestEditPersonalDetails())
            setError('')
            editPersonalDetails({
                name: newName,
                email: newEmail,
                phone: requestPhoneValue,
                country: requestCountryValue,
                oldEmail: email,
        phone_code: newPhoneCode,
            }).then(response => {
                if (response && response.data && response.data.data) {
                    dispatch(actions.successEditPersonalDetails())
                    dispatch(actions.savePersonalDetails(response.data.data))
                    _handleOnModalHide()
                } else {
                    dispatch(actions.errorEditPersonalDetails())
                    if (response.data.errors[0] && response.data.http_message) {
                        setError(response.data.errors[0])
                    } else {
                        setError(intl.formatMessage({
                            id: "error.commonServerError"
                        }))
                    }
                }
            }).catch(error => {
                dispatch(actions.errorEditPersonalDetails())
                setError(intl.formatMessage({
                    id: "error.commonServerError"
                }))
            })
        }
    }, [newName, newEmail, requestPhoneValue, requestCountryValue, isSaveBtnActive])

    // handle response change
    React.useEffect(() => {
        setNewName(name)
    }, [name, setNewName, shouldShowModal])

    React.useEffect(() => {
        setNewEmail(email)
    }, [email, setNewEmail, shouldShowModal])

    React.useEffect(() => {
        setNewPhone(phoneNumber)
        setRequestPhoneValue(phoneNumber)
    }, [phoneNumber, setNewPhone, setRequestPhoneValue, shouldShowModal])

    React.useEffect(() => {
        setNewCountry(getCountryFromCode(country))
        setRequestCountryValue(country)
    }, [country, setNewCountry, setRequestCountryValue, shouldShowModal])

  React.useEffect(() => {
    setNewPhoneCode(phoneCode)
  }, [phoneCode, setNewPhoneCode, shouldShowModal])

    return (
        <div onClick={e => e.stopPropagation()}>
            <Modal 
                show={shouldShowModal} 
                onHide={_handleOnModalHide}
                className="editModal"
                backdropClassName="edit-details-modal-backdrop-custom"
                centered>
                <FormContainer>
                    <BlockUi tag="div" blocking={isRequestLoading}>
                        <Modal.Header className="editModalHeader" closeButton>
                            <Modal.Title>
                                <FormattedMessage id="modal.editPersonalDetails.title"/>
                            </Modal.Title>
                        </Modal.Header>
                        <Modal.Body>
                            <Form>
                                <Form.Group controlId="formBasicPhoneNumber">
                                    <ModalPhoneInput 
                                        initialValue={newPhone}
                                        changeCallback={_phoneChangeCallback}
                    countryChangeCallback={_phoneCountryCodeChangeCallback}
                    defaultCountryCode={newPhoneCode}/>
                                </Form.Group>

                                <SaveDetailsBtn 
                                    disabled={!isSaveBtnActive}
                                    onClick={_handleSaveBtnClick}>
                                    <FormattedMessage id="modal.editPersonalDetails.save"/>
                                </SaveDetailsBtn>
                            </Form>
                        </Modal.Body>
                    </BlockUi>
                </FormContainer>
            </Modal>
        </div>
    )
}

和 PhoneNumberInput 文件:

const PhoneNumberInput = ({ initialValue, customPlaceholder, changeCallback,countryChangeCallback, defaultCountryCode, ...props }) =>  {

    const [countryCode, setCountryCode] = React.useState(defaultCountryCode.toUpperCase())

    const _handleOnCountryCodeChange = React.useCallback((code) => {
        countryChangeCallback(code)
    },[countryChangeCallback])

    React.useEffect(() => {
        if(defaultCountryCode) {
            const countryCodeUpper = defaultCountryCode.toUpperCase()
            setCountryCode(countryCodeUpper)
        }
    },[defaultCountryCode])

    return (
        <PhoneInputWrapper>
            <StyledPhoneInput
                value={value}
                onChange={_handleOnChange} 
                defaultCountry={countryCode}
                onCountryChange={_handleOnCountryCodeChange}  />
        </PhoneInputWrapper>
    )
}

我已經嘗試記錄newPhoneNumber的值並且它按預期工作,除了當我更改值並關閉模式或嘗試保存它時,它記錄未定義並且我得到一個白屏。

錯誤

您可能正在卸載執行一些 ajax 請求的組件,然后根據響應更新狀態。 在獲得響應之前組件已被卸載,但該功能繼續並嘗試更新不再安裝的組件的狀態。

處理此問題的適當方法是將請求存儲在某個數組中,這些數組將通過重新渲染持續存在(例如在 useRef 中)。 然后在組件卸載時,在 useEffect 清理函數中使用 Abort Controller API。

這篇文章可能對你有幫助: https : //medium.com/@selvaganesh93/how-to-clean-up-subscriptions-in-react-components-using-abortcontroller-72335f19b6f7

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM