React Counter with useEffect
Scenario
You have been tasked to build an advanced counter application. This project will challenge you to go beyond simple state updates by requiring you to manage multiple state dependencies, implement side effects using the useEffect
hook (including proper cleanup), and handle more complex state update logic. The goal is to solidify your understanding of useState
and useEffect
in a practical context, focusing on how they work together to create interactive and responsive components.
Learning Objectives
Upon successful completion of this lab, you will be able to:
- Implement and manage multiple pieces of state within a single component using
useState
. - Utilize the
useEffect
hook to perform side effects in response to state changes. - Implement proper cleanup functions within
useEffect
to prevent memory leaks or unexpected behavior. - Write state update logic that correctly handles dependencies and previous state.
- Apply your knowledge to build a feature-rich counter with history tracking, auto-save, keyboard interactions, and a reset mechanism.
Project Requirements
Build a React application that features an advanced counter. The specific features are outlined below.
Core Counter Functionality
- Display Current Count: Show the current count, initialized to 0.
- Increment Button: A button to increase the count by 1.
- Decrement Button: A button to decrease the count by 1.
Advanced Features
-
History Tracking:
- Keep a history of all count values. Every time the count changes, add the new count to an array of previous counts.
- Display this history list to the user (e.g., “Previous counts: 0, 1, 2, 1, 2, 3”).
-
Auto-Save Functionality:
- Use
useEffect
to save the current count to local storage whenever it changes. - Ensure you handle potential race conditions or cleanup if the count changes again before the “save” completes. (Hint: cleanup function in
useEffect
).
- Use
-
Keyboard Event Listeners:
- Allow the user to increment the count by pressing the “ArrowUp” key.
- Allow the user to decrement the count by pressing the “ArrowDown” key.
- Use
useEffect
to add and remove these event listeners to thedocument
. - Ensure event listeners are cleaned up when the component unmounts or is no longer active.
-
Reset Mechanism:
- Implement a button to reset the count back to 0.
- This reset should also clear the tracked history of counts.
-
Step Input:
- Add an input field where the user can define a custom “step” value.
- The increment and decrement buttons should then use this step value instead of 1.
- Consider how changes to the step value affect the counter and its history.
Implementation Guidelines
- Create a new React component for your counter (e.g.,
AdvancedCounter.tsx
). - Use
useState
to manage the current count, history array, and any other necessary local state. - Use
useEffect
for side effects like auto-saving and adding/removing keyboard event listeners. - Pay close attention to the dependency arrays in your
useEffect
hooks to control when they re-run. - Ensure all
useEffect
hooks that set up subscriptions or event listeners have proper cleanup functions.
Example Solution
Counter
Count History:
No history yet.
Submission
Submit your project on Canvas via a GitHub link that includes all necessary files.
Grading Rubric
This lab is graded on a Complete / Incomplete basis. To achieve a “Complete” status, your submission must:
- Successfully implement all Core Counter Functionality.
- Successfully implement at least 3 out of the 4 Advanced Features (History Tracking, Auto-Save, Keyboard Listeners, Reset Mechanism).
- Demonstrate correct usage of
useState
for state management. - Demonstrate correct usage of
useEffect
for side effects, including appropriate dependency arrays. - Implement proper cleanup for any effects that require it (e.g., event listeners, timers from auto-save simulation).
- The application should run without console errors (related to React, not build environment warnings).
Focus on understanding and correctly applying useState
and useEffect
. The visual presentation of the counter is secondary to its functional correctness and the proper use of React Hooks.
Break down each feature into smaller pieces. Test each piece as you go. Use console.log
statements liberally during development to understand state changes and effect executions.