I have this issue where by whenever I refresh the FeedbackDetailView page, the feedback state in the FeedbackDetailView is cleared, which is intended, but I am looking for a way to persist the feedback data. I have tried to use useEffect() to make a call to the API, but the UseEffect() does not run when the page and refreshed, hence the state is still cleared after the refresh. However, when FeedbackDetail navigated from the '/' route, the state is there and the component renders the comments fine. I have used context to save the feedbacks data from API call when the Homepage is rendered but the feedback state is still refreshed and also tried to save the feedback data to localStorage, but still can't get the feedback data to persist. Anyone can help? Thanks!
FeedbackDetailView.js
import { useParams, Link } from "react-router-dom";
import { useState, useContext, useEffect } from "react";
import ButtonTertiary from "../Elements/Buttons/ButtonTertiary";
import FeedbackDetail from "../FeedbackView/FeedbackDetail";
import FeedbackDetailComment from "./FeedbackDetailComment";
import FeedbackContext from "../../contexts/FeedbackContext";
const FeedbackDetailView = () => {
const { feedbacks } = useContext(FeedbackContext);
const id = useParams().id.slice(0, -1);
const feedback = feedbacks.find((feedback) => feedback.id === id);
return (
<div className="p-6 sm:mx-28 md:max-w-xl md:mx-auto">
<div className="mt-8">
<Link to="/">
<ButtonTertiary buttonText="Go Back" />
</Link>
</div>
<FeedbackDetail feedback={feedback} />
<div className="p-6 bg-white rounded-lg mt-14 md:mx-auto">
<h1 className="text-lg font-bold text-navy-primary">
{feedback.comments.length}{" "}
{feedback.comments.length === 1 ? "Comment" : "Comments"}
</h1>
{feedback.comments.length !== 0 ? (
<div className="mt-2 border-grey-50">
{feedback.comments.map((comment, index) => (
<FeedbackDetailComment key={index} comment={comment} />
))}
</div>
) : (
""
)}
</div>
<div className="p-6 bg-white rounded-lg mt-14 md:mx-auto">
<h1 className="text-lg font-bold text-navy-primary">Add a comment</h1>
<p className="text-sm font-light text-navy-tertiary">
Max 250 characters.
</p>
<textarea className="mt-4 bg-main-secondary text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full h-24 p-2.5"></textarea>
<div className="flex w-full justify-items-end">
<button
type="submit"
className="px-6 py-3 mt-4 ml-auto text-sm font-semibold leading-5 text-center text-white rounded-lg cursor-pointer text-b bg-fuchsia-600 hover:bg-fuchsia-400"
>
Add Comment
</button>
</div>
</div>
</div>
);
};
export default FeedbackDetailView;
Homepage.js
const Homepage = () => {
const [open, setOpen] = useState(false);
const [showFeedbacks, setShowFeedbacks] = useState(false);
const [sortOption, setSortOption] = useState("Most Upvotes");
const [selectedCategory, setSelectedCategory] = useState("All");
const { feedbacks, setFeedbacks } = useContext(FeedbackContext);
const { message, type } = useContext(NotificationContext);
const { setLoggedInUser } = useContext(UserContext);
useEffect(() => {
feedbackService.getAll().then((initialFeedbacks) => {
setFeedbacks(initialFeedbacks.sort((a, b) => b.upvotes - a.upvotes));
});
}, []);
useEffect(() => {
const loggedUserJson = window.localStorage.getItem("loggedFeedbackAppUser");
if (loggedUserJson) {
const user = JSON.parse(loggedUserJson);
setLoggedInUser(user);
feedbackService.setToken(user.token);
}
}, []);
useEffect(() => {
if (feedbacks.length > 0) {
setShowFeedbacks(true);
}
}, [feedbacks.length]);
const handleSlideoverOpen = () => {
setOpen(!open);
};
const updateSortOption = (sort) => {
setSortOption(sort);
};
const sortedFeedbacks = (feedbacks) => {
if (sortOption === "Most Upvotes") {
return feedbacks.sort((a, b) => b.upvotes - a.upvotes);
} else if (sortOption === "Least Upvotes") {
return feedbacks.sort((a, b) => a.upvotes - b.upvotes);
} else if (sortOption === "Most Comments") {
return feedbacks.sort((a, b) => b.comments.length - a.comments.length);
} else if (sortOption === "Least Comments") {
return feedbacks.sort((a, b) => a.comments.length - b.comments.length);
}
};
return (
<div className="container p-0 mx-auto sm:mt-14 md:px-9">
<Alerts type={type} message={message} />
{/* When screen is > 1024px (Desktop Screens) */}
<div className="hidden lg:contents">
<div className="flex flex-row gap-x-8">
<div className="flex flex-col gap-y-6">
<Hero handleSlideoverOpen={handleSlideoverOpen} open={open} />
<FeedbackCategory />
</div>
<div className="flex flex-col w-full">
<FeedbackNavbar
feedbackNum={feedbacks.length}
sortOption={sortOption}
updateSortOption={updateSortOption}
/>
<FeedbackList
feedbacks={sortedFeedbacks(feedbacks)}
showFeedbacks={showFeedbacks}
sortOption={sortOption}
/>
</div>
</div>
</div>
{/* When screen is > 768px (Tablet Screens) */}
<div className="hidden sm:contents lg:hidden">
<div className="flex flex-row justify-between mb-10">
<Hero handleSlideoverOpen={handleSlideoverOpen} open={open} />
<FeedbackCategory
selectedCategory={selectedCategory}
setSelectedCategory={setSelectedCategory}
/>
</div>
</div>
{/* When screen is < 640px (Mobile Screens) */}
<div className="sm:hidden">
<Hero handleSlideoverOpen={handleSlideoverOpen} open={open} />
</div>
<div className="hidden">
<FeedbackCategory />
</div>
{/* Slideover */}
<div className="sm:hidden">
<Slideover open={open} setOpen={handleSlideoverOpen} />
</div>
<div className="lg:hidden">
<FeedbackNavbar
feedbackNum={feedbacks.length}
sortOption={sortOption}
updateSortOption={updateSortOption}
/>
<FeedbackList feedbacks={feedbacks} showFeedbacks={showFeedbacks} />
</div>
</div>
);
};
export default Homepage;
FeedbackContext.js
import { createContext, useState, useEffect } from "react";
const FeedbackContext = createContext();
export const FeedbackProvider = ({ children }) => {
const [feedbacks, setFeedbacks] = useState([]);
return (
<FeedbackContext.Provider value={{ feedbacks, setFeedbacks }}>
{children}
</FeedbackContext.Provider>
);
};
export default FeedbackContext;
App.js
import { Route, Routes } from "react-router-dom";
import Homepage from "./components/Homepage/Homepage";
import AddFeedbackForm from "./components/AddFeedback/AddFeedbackForm";
import LoginPage from "./components/Login/LoginPage";
import RegisterPage from "./components/Login/RegisterPage";
import FeedbackDetailView from "./components/FeedbackView/FeedbackDetailView";
import { NotificationProvider } from "./contexts/NotificationContext";
import { UserProvider } from "./contexts/UserContext";
import { FeedbackProvider } from "./contexts/FeedbackContext";
const App = () => {
return (
<div>
<FeedbackProvider>
<UserProvider>
<NotificationProvider>
<Routes>
<Route path="/" element={<Homepage />} exact />
<Route path="/add-feedback" element={<AddFeedbackForm />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/register" element={<RegisterPage />} />
<Route path="/feedbacks/:id" element={<FeedbackDetailView />} />
</Routes>
</NotificationProvider>
</UserProvider>
</FeedbackProvider>
</div>
);
};
export default App;