Projects
Chat App
Master building a React Chat App, covering message lists, active channel selectors, auto-scroll controls using useRef, and simulated responses.
1. Learning Objectives
In this project, you will build a responsive Chat Application. By the end of this project, you will be able to:
- Orchestrate multi-channel message states using key-value pair structures in state.
- Manage scroll positions and auto-scroll messages to the bottom using
useRef. - Simulate delayed bot replies using asynchronous timers inside effects.
- Implement user status badges (Online, Away, Offline) dynamically.
- Build responsive layouts containing contact list panels and chat windows.
2. Overview
A **Chat Application** covers state manipulation, lists indexing, side effects (simulating live messaging feeds), and DOM node control. We will build a chat application with auto-scrolling capabilities and simulated bot responses.
3. Why This Project Matters
Chat applications require precise DOM control and asynchronous coordination:
- DOM Element Control: When new messages arrive, users expect the window to scroll to the bottom automatically. This requires using
useRefto read and update DOM node coordinates. - Asynchronous State Flow: You learn how to trigger side effects (like bot replies) that respond to state updates safely.
4. Real-World Analogy
Think of a Chat Application like **a post office message tube system**:
- The Channels: Different mailboxes for different departments (channel states).
- Auto-scroll: A sorting machine that automatically pushes the most recent letter to the front of the pile so it is read first, rather than leaving it hidden at the bottom (updating scroll heights dynamically using refs).
- The Bot Response: An automatic return slip mailed back to you 2 seconds after your package is scanned (simulated async response).
5. Core Concepts
Below is a comparison of standard list scroll behavior and auto-scrolling:
| Property | Standard Scroll Behavior | Auto-Scrolling (using Refs) |
|---|---|---|
| Implementation | Standard CSS overflow container handles scroll position manually. | A useRef element points to the bottom of the container and triggers scroll updates. |
| User Experience | Users must scroll down manually to see new messages. | The chat window scrolls to the bottom automatically when new messages arrive. |
| DOM Access | None; purely declarative JSX rendering. | Requires imperative access to the DOM node using scrollIntoView(). |
6. Syntax & API Reference
This example shows how to configure auto-scrolling using a DOM ref:
7. Visual Diagram
This diagram displays how state updates trigger DOM scrolling:
8. Live Example — Full Working Code
Below is a complete HTML page demonstrating a working chat interface with auto-scrolling and simulated bot responses:
What just happened? Submitting the form appends the user's message to state, triggering a re-render. The useEffect hook immediately scrolls the new message bubble into view. A second effect detects the user's message and triggers a simulated bot reply after a 1.5-second delay.
9. Interactive Playground
Try It Yourself Challenges:
- Change the scroll behavior option in
scrollIntoViewto"auto"and verify that scrolling happens instantly instead of smoothly. - Add a "Typing..." status indicator that appears while the bot is preparing its response.
10. Common Mistakes
| Mistake | Why it happens | Wrong | Correct |
|---|---|---|---|
| Calling DOM scroll methods during rendering | Calling scroll methods (like scrollIntoView) directly in the component body runs the method *before* the DOM has updated, meaning the new message elements aren't rendered yet, resulting in incorrect scroll positions. |
Calling bottomRef.current.scrollIntoView() directly inside the render loop. |
Call scroll methods inside a useEffect hook, which runs *after* the DOM has been updated. |
| Forgetting to clean up bot reply timers | If the user sends multiple messages quickly, multiple bot timers start. If the component unmounts before these timers finish, React will try to update state on an unmounted component, throwing console warnings. | Starting timers inside an effect without returning a cleanup function. | Always save the timer ID (const id = setTimeout(...)) and call clearTimeout(id) in the cleanup function. |
11. Best Practices
- Scroll inside effects: Always call scroll methods (like
scrollIntoView) inside auseEffecthook to ensure the DOM has updated. - Clean up bot response timers: Always return a cleanup function that clears any active timeouts or intervals.
- Use key-value pairs for chat messages: Store messages in a key-value object (e.g. `{ [channelId]: [messages] }`) to make switching channels faster and cleaner.
- Add scroll anchors: Place a dummy empty `div` at the bottom of the scroll container to act as a scroll target.
12. Browser Compatibility/Requirements
This project requires browser support for scrollIntoView (supported in all modern browsers).
13. Interview Questions
Q1: How do you implement auto-scrolling to the bottom of a container in React when a list updates?
Answer: Declare a ref: `const bottomRef = useRef(null)`. Place an empty div at the bottom of the scroll container: `
Q2: Why does React warn about state updates on unmounted components? How do you prevent it?
Answer: React warns about state updates on unmounted components when an asynchronous process (like an API fetch or timeout) attempts to update state after the component has unmounted. To prevent this, clear any active timers or cancel subscriptions inside the cleanup function returned by the `useEffect` hook.
14. Debugging Exercise
Identify why this chat window scrolls to the bottom only on the first message, but ignores subsequent messages:
Diagnosis: The useEffect hook has an empty dependency array ([]), meaning it runs only once when the component mounts. Because of this, it ignores subsequent updates to the messages array.
Fix: Add the messages array to the hook's dependency array to trigger scroll updates on every new message:
15. Practice Exercises
Exercise 1: Add a typing status indicator
Extend the chat application by adding a isTyping state variable. Display a "Support is typing..." indicator for 1 second before the bot reply mounts in the messages feed.
16. Scenario-Based Challenge
The Multi-Room Socket Connection manager:
You are designing a chat portal supporting dozens of chat rooms. Switching rooms should close the active socket connection and open a new one for the selected room, loading its message history. Describe how you would implement this lifecycle logic inside a useEffect hook.
17. Quick Quiz
Q1: Which hook is used to reference and interact with a DOM node directly in React?
A) useState()
B) useRef()
C) useMemo()
Answer: B — The useRef() hook returns a mutable ref object whose .current property references the target DOM node.
18. Summary & Key Takeaways
- Call DOM scroll methods (like
scrollIntoView) inside auseEffecthook to ensure the DOM has updated. - Always clear timers and subscriptions in your cleanup functions to prevent memory leaks.
- Use key-value objects to map and manage messages across multiple channels cleanly.
- Use refs to interact with DOM nodes directly for scroll or focus management.
19. Cheat Sheet
| Ref Scroll Operation | Syntax Example |
|---|---|
const ref = useRef(null) |
Creates a ref object to anchor a DOM node target. |
<div ref={ref} /> |
Binds the ref object to the target DOM node. |
ref.current.scrollIntoView({ behavior: 'smooth' }) |
Scrolls the referenced DOM node into the visible area of the browser window. |