reactjs - 取消 useEffect 清理函数中的所有订阅和异步任务 - 我做错了什么?
问题描述
我正在尝试根据用户是否登录来更改按钮。该功能由 MyNav.js 管理。如果用户已登录,我会显示退出按钮,否则,我会显示登录和注册按钮。如果您能指导我做错了什么,那就太好了。
警告:
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.
at LoginSigninModal (http://localhost:3000/static/js/main.chunk.js:530:81)
at MenuButtons
MyNav.js
import React, { useEffect, useState } from 'react'
import Nav from 'react-bootstrap/Nav'
import Navbar from 'react-bootstrap/Navbar'
// import NavDropdown from 'react-bootstrap/NavDropdown'
import { Link } from 'react-router-dom'
import Searchfield from '../product_search_components/Searchfield'
import LoginSignout from '../login_components/LoginSignout'
import MenuButtons from './MenuButtons'
export default function MyNav(props) {
var isSigned
if (localStorage.getItem('scs_user_logged_in')){
isSigned = true
}else{
isSigned = false
}
const [signedIn, setSignedIn] = useState(isSigned)
var menu
if (signedIn) {
menu = <LoginSignout setSignedIn={setSignedIn}/>
} else {
menu = <MenuButtons setSignedIn={setSignedIn}/>
}
useEffect(()=>{
},[signedIn])
return (
<Navbar bg="light" expand="lg">
<Navbar.Brand><span style={{ fontWeight: 'bold' }}>Test</span></Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="mr-auto">
<Link className='nav-link' to="/">Home</Link>
<Link className='nav-link' to="/about">About</Link>
<Link className='nav-link' to="/todo">Todo</Link>
{/* <NavDropdown title="Dropdown" id="basic-nav-dropdown">
<NavDropdown.Item>Action</NavDropdown.Item>
<NavDropdown.Item>Another action</NavDropdown.Item>
<NavDropdown.Item>Something</NavDropdown.Item>
<NavDropdown.Divider />
<NavDropdown.Item>Separated link</NavDropdown.Item>
</NavDropdown> */}
</Nav>
</Navbar.Collapse>
<Searchfield search_item={props.search_item} setSearchItem={props.setSearchItem} />
{menu}
</Navbar>
)
}
菜单按钮.js
import LoginSigninModal from '../login_components/LoginSigninModal'
import LoginSignupModal from '../login_components/LoginSignupModal'
export default function MenuButtons(props) {
return (
<>
<LoginSigninModal {...props}/>
<LoginSignupModal />
</>
)
}
登录SigninModal.js
import React, { useState, useEffect } from 'react'
import Button from 'react-bootstrap/Button'
import Modal from 'react-bootstrap/Modal'
import Form from 'react-bootstrap/Form'
import Alert from 'react-bootstrap/Alert'
import Spinner from 'react-bootstrap/Spinner'
import { baseURL } from './../assets/axiosInstance'
import axios from 'axios'
// import LoginSignupModal from './LoginSignupModal'
export default function LoginSigninModal(props) {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const [localSigned, setLocalSigned] = useState(false)
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const errorEmail = false
const [apiCalling, setApiCalling] = useState(false)
const [messageOnSubmit, setMessageOnSubmit] = useState({
type: "",
message: ""
})
useEffect(() => {
props.setSignedIn(localSigned)
}, [localSigned, props])
function handleSubmit() {
setApiCalling(true)
const getData = async () => {
await axios.post(baseURL + 'auth/login', {
email: email,
password: password,
})
.then((response) => {
localStorage.setItem('scs_token', response.data['access_token'])
localStorage.setItem('scs_user', JSON.stringify(response.data['user']))
localStorage.setItem('scs_user_logged_in', true)
setLocalSigned(true)
setMessageOnSubmit({
type: "success",
message: "Login Successful"
})
})
.catch((error) => {
console.log(error.response.status)
if(error.response.status === 401){
setMessageOnSubmit({
type: "danger",
message: "Login failed due to wrong password."
})
}else if(error.response.status === 422){
setMessageOnSubmit({
type: "danger",
message: "Password needs to be at least 6 characters long."
})
}
})
.then(()=>{
setApiCalling(false)
})
}
getData()
}
return (
<>
<Button variant="primary" onClick={handleShow} style={{ marginLeft: '5px' }}>
Signin
</Button>
<Modal
show={show}
onHide={handleClose}
backdrop="static"
keyboard={false}
>
<Modal.Header closeButton>
<Modal.Title>Signin</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control value={email} onChange={(data) => setEmail(data.target.value)} type="email" placeholder="xyz@email.com" />
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control value={password} onChange={(data) => setPassword(data.target.value)} type="password" placeholder="Password" />
</Form.Group>
{(
messageOnSubmit['type'] !== ""
?
<Alert variant={messageOnSubmit['type']}>
{messageOnSubmit['message']}
</Alert>
:
"")}
<Button variant="primary" type="button" disabled={errorEmail} active={!errorEmail} onClick={handleSubmit}>Login {apiCalling && <Spinner animation="border" size="sm" />}</Button>
<Button variant="secondary" onClick={handleClose} style={{ marginLeft: "5px" }}>Close</Button>
</Form>
</Modal.Body>
<Modal.Footer>
</Modal.Footer>
</Modal>
</>
);
}
http://localhost:3000/static/js/main.chunk.js:530:81 - (来自警告消息)
function LoginSigninModal(props) {
_s();
const [show, setShow] = Object(react__WEBPACK_IMPORTED_MODULE_1__["useState"])(--error marked here--)(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
解决方案
问题出在 LoginSigninModal.js 的以下代码块中
.then((response) => {
localStorage.setItem('scs_token', response.data['access_token'])
localStorage.setItem('scs_user', JSON.stringify(response.data['user']))
localStorage.setItem('scs_user_logged_in', true)
setLocalSigned(true)
setMessageOnSubmit({
type: "success",
message: "Login Successful"
})
})
成功登录后,我更改了 localSigned 状态。卸载登录模式组件。然后我尝试更新该组件上的消息。由于组件已卸载,因此出现错误。删除 setMessageonSubmit 或在 setMessageSubmit 后调用 set setLocalSigned 可解决问题。
正确的代码将是:
.then((response) => {
localStorage.setItem('scs_token', response.data['access_token'])
localStorage.setItem('scs_user', JSON.stringify(response.data['user']))
localStorage.setItem('scs_user_logged_in', true)
setMessageOnSubmit({
type: "success",
message: "Login Successful"
})
setLocalSigned(true)
})
或者
.then((response) => {
localStorage.setItem('scs_token', response.data['access_token'])
localStorage.setItem('scs_user', JSON.stringify(response.data['user']))
localStorage.setItem('scs_user_logged_in', true)
setLocalSigned(true)
})
推荐阅读
- python - 使用 chunksize 从 s3 将 CSV 文件加载到 Pandas
- angular - Angular - 管道和 elvis 运算符 (?) 导致更快地调用 getter
- nginx - NGINX 背后的 Kubectl 代理:无效的升级响应
- javascript-automation - JXA '无法转换类型'
- pytorch - 无法使用 transforms.Resize 重新缩放图像
- laravel - Laravel 合集搜索
- javascript - express API 没有执行我最近的更改
- python-3.x - pandas 数据框中的单元格具有 Excel 工作簿中不存在的异常符号
- spring - Spring中如何解决双bean冲突
- javascript - 如何在本机反应中单击图标打开侧边菜单