[英]React: SetInterval in ComponentDidMount causing error "Warning: Can't perform a React state update on an unmounted component."
[英]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.