I'm writing my first react-typescript application and I'm seeing the following warning which may be causing some issue which I'm trying to solve.
index.js:1 Warning: 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.
I'm not able to fathom this warning so could anyone help me out here to find out why this is happening.
The code where this error is occurring is following:
Finished.tsx
import Grid from "@material-ui/core/Grid";
import { useQuery } from "react-query";
import Book, { BookType } from '../Book/Book'
import LinearProgress from '@material-ui/core/LinearProgress';
const getBooks = async (): Promise<BookType[]> =>
await (await fetch(`${process.env.REACT_APP_API_BASE_URL}/books/finished`, {
headers: {'Content-Type': 'application/json'},
credentials: 'include',
})).json()
const Finished = () => {
const { isFetching, isLoading, isLoadingError, isError, data } = useQuery<BookType[] | undefined>(
'books',
getBooks
)
if (isLoading || isFetching) {
return (
<LinearProgress />
)
}
if (isLoadingError || isError) {
return (
<h3 style={{color: "red", textAlign: "center"}}>
Empty bookshelf
</h3>
)
}
return (
<Grid container spacing={2}>
{data?.map(book => (
<Grid item key={book.id} xs={12} sm={2}>
<Book book={book}/>
</Grid>
))}
</Grid>
)
}
export default Finished
Modal.tsx
import { SyntheticEvent, useState } from "react";
import { Modal, Button } from "react-bootstrap";
import { BookType } from '../Book/Book'
import UpdateForm from '../Components/UpdateForm'
const MyModal = (props: {show: boolean, book: BookType, setShow: (status: boolean) => void }) => {
const [reload, setReload] = useState(false)
const [error, setError] = useState(<></>)
const bookId = props.book.id
const bookName = props.book.name
const handleClose = () => {
props.setShow(false);
if (reload) {
window.location.reload()
}
}
const deleteBook = async (e: SyntheticEvent) => {
e.preventDefault()
if (window.confirm("Are you sure?")) {
const response = await fetch(`${process.env.REACT_APP_API_BASE_URL}/books/deletebook`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
credentials: 'include',
body: JSON.stringify({
"id": bookId,
"name": bookName
})
});
const content = await response.json();
if (content.status !== 200) {
setError((
<div className="alert alert-danger" role="alert">
{content.message}
</div>
))
} else {
setError((
<div className="alert alert-warning" role="alert">
{content.message}
</div>
))
setReload(true)
}
}
}
return (
<Modal
show={props.show}
onHide={handleClose}
backdrop="static"
keyboard={false}
>
<Modal.Header>
<Modal.Title>
<i>{bookName}</i>
</Modal.Title>
</Modal.Header>
<Modal.Body>
{error}
<b><i>Book Status: {props.book.status.toUpperCase()}</i></b>
<pre></pre>
<UpdateForm bookId={bookId} setReload={setReload}/>
</Modal.Body>
<Modal.Footer>
<Button variant="danger" onClick={deleteBook}>Delete Book</Button>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
</Modal.Footer>
</Modal>
);
}
export default MyModal
UpdateForm.tsx
import { useState, SyntheticEvent } from "react";
const UpdateForm = (props: {bookId: string, setReload: (reload: boolean) => void}) => {
const [bookStatus, setBookStatus] = useState('reading')
const [error, setError] = useState(<></>)
const bookId = props.bookId
const submit = async (e: SyntheticEvent) => {
e.preventDefault();
if (window.confirm(`Do you want to move this book to ${bookStatus}?`)) {
const response = await fetch(`${process.env.REACT_APP_API_BASE_URL}/books/updatestatus`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
credentials: 'include',
body: JSON.stringify({
"status": bookStatus,
"id": bookId
})
});
const content = await response.json();
console.log(bookStatus)
if (content.status !== 200) {
setError((
<div className="alert alert-danger" role="alert">
{content.message}
</div>
))
} else {
setError((
<div className="alert alert-success" role="alert">
{content.message}
</div>
))
props.setReload(true)
}
}
}
return (
<div className="row">
<div className="col">
{error}
<form className="row g-3" onSubmit={submit}>
<div className="col-md-6">
<select className="form-select" defaultValue="reading" required
onChange={e => setBookStatus(e.target.value)}
>
<option value="reading">Reading</option>
<option value="finished">Finished</option>
<option value="wishlist">Wishlist</option>
</select>
</div>
<div className="col-md-6">
<button type="submit" className="btn btn-primary">Update</button>
</div>
</form>
</div>
</div>
)
}
export default UpdateForm
The complete error stack trace is:
index.js:1 Warning: 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 UpdateForm (http://localhost:3000/static/js/main.chunk.js:1240:93)
at div
at http://localhost:3000/static/js/vendors~main.chunk.js:26915:27
at div
at div
at http://localhost:3000/static/js/vendors~main.chunk.js:23980:23
at div
at Transition (http://localhost:3000/static/js/vendors~main.chunk.js:65502:30)
at http://localhost:3000/static/js/vendors~main.chunk.js:22211:24
at DialogTransition
at http://localhost:3000/static/js/vendors~main.chunk.js:57183:24
at http://localhost:3000/static/js/vendors~main.chunk.js:23657:23
at MyModal (http://localhost:3000/static/js/main.chunk.js:692:85)
at div
at O (http://localhost:3000/static/js/vendors~main.chunk.js:71801:6)
at Book (http://localhost:3000/static/js/main.chunk.js:505:81)
at div
at Grid (http://localhost:3000/static/js/vendors~main.chunk.js:1445:35)
at WithStyles (http://localhost:3000/static/js/vendors~main.chunk.js:5136:31)
at div
at Grid (http://localhost:3000/static/js/vendors~main.chunk.js:1445:35)
at WithStyles (http://localhost:3000/static/js/vendors~main.chunk.js:5136:31)
index.js:1 Warning: 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 MyModal (http://localhost:3000/static/js/main.chunk.js:692:85)
at div
at O (http://localhost:3000/static/js/vendors~main.chunk.js:71801:6)
at Book (http://localhost:3000/static/js/main.chunk.js:505:81)
at div
at Grid (http://localhost:3000/static/js/vendors~main.chunk.js:1445:35)
at WithStyles (http://localhost:3000/static/js/vendors~main.chunk.js:5136:31)
at div
at Grid (http://localhost:3000/static/js/vendors~main.chunk.js:1445:35)
at WithStyles (http://localhost:3000/static/js/vendors~main.chunk.js:5136:31)