Update your portfolio pages from fetching data using useEffect and useState and replace them with useQuery from TanStack Query.
After the refactor:
useEffect and the manual loading/error state variables should be goneisPending, errors via isErrorThe current theme toggle uses useState and the choice resets on every reload. Add localStorage persistence and keep it SSR-safe now that the toggle lives inside a Next.js Client Component.
The implementation must:
localStorage under a clearly named key (e.g. 'theme')useEffect and apply it to <html>localStorage at the top of the Client Component - that would throw localStorage is not defined during the server render. Either keep the read inside useEffect or guard it with typeof window !== 'undefined'Verify in DevTools → Application → Local Storage that the value is written, and confirm the choice survives both a page reload and closing/reopening the browser.
Add a like button with a visible count to each item on the /projects page you built in Task 1. The count must update in the UI the instant the button is clicked - before the network request finishes.
Use useMutation with all three lifecycle callbacks:
onMutate must call queryClient.cancelQueries on the projects query, snapshot the current cached value with getQueryData, and increment the clicked item's like count in the cache via setQueryData. Return the snapshot in the context object so onError can read it.onError must restore the snapshot from the context object back into the cache.onSettled must invalidate the projects query.You can add a new field in your data source to get the initial value side. You don't need a real backend for the updating the count. A mutationFn that resolves after a short delay is enough:
mutationFn: async (projectId: number) => {
await new Promise(r => setTimeout(r, 500))
}
To verify the rollback, temporarily change the mutationFn to throw after the delay:
mutationFn: async (projectId: number) => {
await new Promise(r => setTimeout(r, 800))
throw new Error('Simulated failure')
}
Click the button. The count must increment the moment you click, then decrement 800ms later when onError fires.
Follow the Assignment submission guide to learn how to submit the assignment.
The HackYourFuture curriculum is licensed under CC BY-NC-SA 4.0 *https://hackyourfuture.net/*

Built with ❤️ by the HackYourFuture community · Thank you, contributors
Found a mistake or have a suggestion? Let us know in the feedback form.