In my React App, I'm displaying all the books with author name. User can delete a book by clicking an item. Thing is I want to refresh the page without reloading the entire page. States are the way to go for such kind of situations but it still doesn't refresh the component.
Can anybody suggest any ideas?
App.tsx
import React, { useLayoutEffect, useState } from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { getAllBooks } from "./api_actions/api_calls";
import "./App.css";
import AllBooks from "./components/AllBooks";
import InsertBooks from "./components/InsertBook";
import { Book } from "./models/Book";
function App() {
const [myBooks, setMyBooks] = useState<Book[]>([]);
useLayoutEffect(() => {
getAllBooks().then((orders) => {
setMyBooks(orders);
});
}, []);
return (
<div className="App">
<header className="App-header">
<BrowserRouter>
<Routes>
<Route path="/" element={<AllBooks books={myBooks} />} />
<Route path="/add" element={<InsertBooks />} />
</Routes>
</BrowserRouter>
</header>
</div>
);
}
export default App;
Component that displays all the books, AllBooks.tsx:
interface IAllBooksProps {
books: Book[];
}
const AllBooks: React.FC<IAllBooksProps> = (props) => {
const [lastDeletedTitle, setLastDeletedTitle] = useState("");
const handleDeleteBook = (title: string) => {
console.log("Trying to delete...", title);
deleteBook(title).then((response) => {
setLastDeletedTitle(title);
});
};
useEffect(() => {
if (lastDeletedTitle !== "") {
toast(`${lastDeletedTitle} has been deleted!`);
}
}, [lastDeletedTitle]);
return (
<>
{props.books?.map((book) => {
return <Card key={book.id} book={book} onDelete={handleDeleteBook} />;
})}
<ToastContainer />
</>
);
};
Bring changes in AllBooks.tsx like bellow
const AllBooks: React.FC<IAllBooksProps> = (props) => {
const [books, setBooks] = useState(props.books); //props.books set in books state
const [lastDeletedTitle, setLastDeletedTitle] = useState("");
const handleDeleteBook = (title: string) => {
console.log("Trying to delete...", title);
deleteBook(title).then((response) => {
setLastDeletedTitle(title);
});
};
useEffect(() => {
if (lastDeletedTitle !== "") {
toast(`${lastDeletedTitle} has been deleted!`);
//recall the getAllBooks here
getAllBooks().then((orders) => {
setBooks(orders); //reset books
});
}
}, [lastDeletedTitle]);
return (
<>
//return books here
{books?.map((book) => {
return <Card key={book.id} book={book} onDelete={handleDeleteBook} />;
})}
<ToastContainer />
</>
);
};
It is better not to call getAllBooks in App.tsx. You just need to call getAllBooks inside your delete function and useEffect in AllBooks.tsx. Try the code given below,
AllBooks.tsx
interface IAllBooksProps {
books: Book[];
}
const AllBooks: React.FC<IAllBooksProps> = (props) => {
const [lastDeletedTitle, setLastDeletedTitle] = useState("");
useEffect(() => {
getBooks();
}, [])
const getBooks = () => {
getAllBooks().then((orders) => {
setMyBooks(orders);
});
}
const handleDeleteBook = (title: string) => {
console.log("Trying to delete...", title);
deleteBook(title).then((response) => {
setLastDeletedTitle(title);
getBooks();
});
};
useEffect(() => {
if (lastDeletedTitle !== "") {
toast(`${lastDeletedTitle} has been deleted!`);
}
}, [lastDeletedTitle]);
return (
<>
{props.books?.map((book) => {
return <Card key={book.id} book={book} onDelete={handleDeleteBook} />;
})}
<ToastContainer />
</>
);
};