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
useEffecthook to perform side effects in response to state changes. - Implement proper cleanup functions within
useEffectto 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
useEffectto 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
useEffectto 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
useStateto manage the current count, history array, and any other necessary local state. - Use
useEffectfor side effects like auto-saving and adding/removing keyboard event listeners. - Pay close attention to the dependency arrays in your
useEffecthooks to control when they re-run. - Ensure all
useEffecthooks 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
useStatefor state management. - Demonstrate correct usage of
useEffectfor 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.