Last active
September 23, 2025 07:05
-
-
Save prathamdby/b053013a76f1b919cc962a191bdde1df to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| globs: "**/*.{ts,tsx,js,jsx}" | |
| alwaysApply: true | |
| --- | |
| # You Might Not Need an Effect - React Documentation Summary | |
| ## Overview | |
| Effects are an escape hatch from the React paradigm that let you "step outside" of React and synchronize your components with external systems like non-React widgets, network requests, or the browser DOM. However, if there's no external system involved, you shouldn't need an Effect. Removing unnecessary Effects makes your code easier to follow, faster to run, and less error-prone. | |
| ## Key Principle | |
| **Effects should only be used to synchronize with external systems.** If you want to update a component's state when some props or state change, you typically don't need an Effect. | |
| ## Common Cases Where You Don't Need Effects | |
| ### 1. Transforming Data for Rendering | |
| **❌ Avoid:** Using Effects to transform data for rendering | |
| ```javascript | |
| // Bad: Redundant state and unnecessary Effect | |
| const [fullName, setFullName] = useState(""); | |
| useEffect(() => { | |
| setFullName(firstName + " " + lastName); | |
| }, [firstName, lastName]); | |
| ``` | |
| **✅ Good:** Calculate during rendering | |
| ```javascript | |
| // Good: calculated during rendering | |
| const fullName = firstName + " " + lastName; | |
| ``` | |
| **Rule:** When something can be calculated from existing props or state, don't put it in state. Instead, calculate it during rendering. | |
| ### 2. Handling User Events | |
| **❌ Avoid:** Using Effects to handle user events | |
| ```javascript | |
| // Bad: Effect for user interaction | |
| useEffect(() => { | |
| if (shouldBuy) { | |
| fetch("/api/buy", { method: "POST" }); | |
| showNotification("Purchase successful!"); | |
| } | |
| }, [shouldBuy]); | |
| ``` | |
| **✅ Good:** Handle in event handlers | |
| ```javascript | |
| // Good: Handle in event handler | |
| function handleBuyClick() { | |
| fetch("/api/buy", { method: "POST" }); | |
| showNotification("Purchase successful!"); | |
| } | |
| ``` | |
| ## Advanced Patterns | |
| ### Caching Expensive Calculations | |
| For expensive computations that don't need to run on every render: | |
| ```javascript | |
| import { useMemo, useState } from "react"; | |
| function TodoList({ todos, filter }) { | |
| const [newTodo, setNewTodo] = useState(""); | |
| // ✅ Cached calculation | |
| const visibleTodos = useMemo(() => { | |
| return getFilteredTodos(todos, filter); | |
| }, [todos, filter]); | |
| // ... | |
| } | |
| ``` | |
| **Note:** React Compiler can automatically memoize expensive calculations, eliminating the need for manual `useMemo` in many cases. | |
| ### Resetting State When Props Change | |
| **❌ Avoid:** Using Effects to reset state | |
| ```javascript | |
| // Bad: Effect to reset state | |
| useEffect(() => { | |
| setComment(""); | |
| }, [userId]); | |
| ``` | |
| **✅ Good:** Reset during rendering | |
| ```javascript | |
| // Good: Reset during rendering | |
| function ProfilePage({ userId }) { | |
| const [comment, setComment] = useState(""); | |
| // Reset comment when userId changes | |
| const [prevUserId, setPrevUserId] = useState(userId); | |
| if (userId !== prevUserId) { | |
| setComment(""); | |
| setPrevUserId(userId); | |
| } | |
| // ... | |
| } | |
| ``` | |
| **Alternative:** Use a `key` prop to reset entire component tree: | |
| ```javascript | |
| <ProfilePage userId={userId} key={userId} /> | |
| ``` | |
| ### Adjusting State When Props Change | |
| **❌ Avoid:** Using Effects to adjust state | |
| ```javascript | |
| // Bad: Effect to adjust state | |
| useEffect(() => { | |
| setSelection(items[0]); | |
| }, [items]); | |
| ``` | |
| **✅ Good:** Adjust during rendering | |
| ```javascript | |
| // Good: Adjust during rendering | |
| function List({ items }) { | |
| const [isReverse, setIsReverse] = useState(false); | |
| const [selection, setSelection] = useState(null); | |
| // Better: Adjust during rendering | |
| const [prevItems, setPrevItems] = useState(items); | |
| if (items !== prevItems) { | |
| setPrevItems(items); | |
| if (selection === null || !items.includes(selection)) { | |
| setSelection(items[0]); | |
| } | |
| } | |
| // ... | |
| } | |
| ``` | |
| ## When You DO Need Effects | |
| ### 1. Synchronizing with External Systems | |
| Effects are appropriate for: | |
| - Keeping a jQuery widget synchronized with React state | |
| - Setting up subscriptions to external data sources | |
| - Manually manipulating the DOM | |
| - Logging analytics events | |
| ### 2. Data Fetching (with proper cleanup) | |
| ```javascript | |
| function SearchResults({ query }) { | |
| const [results, setResults] = useState([]); | |
| const [page, setPage] = useState(1); | |
| useEffect(() => { | |
| let ignore = false; | |
| fetchResults(query, page).then((json) => { | |
| if (!ignore) { | |
| setResults(json); | |
| } | |
| }); | |
| return () => { | |
| ignore = true; // Cleanup to prevent race conditions | |
| }; | |
| }, [query, page]); | |
| // ... | |
| } | |
| ``` | |
| **Important:** Always implement cleanup logic to avoid race conditions when fetching data. | |
| ## Best Practices | |
| ### Custom Hooks for Data Fetching | |
| Extract data fetching logic into custom hooks for better reusability: | |
| ```javascript | |
| function useData(url) { | |
| const [data, setData] = useState(null); | |
| useEffect(() => { | |
| let ignore = false; | |
| fetch(url) | |
| .then((response) => response.json()) | |
| .then((json) => { | |
| if (!ignore) { | |
| setData(json); | |
| } | |
| }); | |
| return () => { | |
| ignore = true; | |
| }; | |
| }, [url]); | |
| return data; | |
| } | |
| ``` | |
| ### Sharing Logic Between Event Handlers | |
| **❌ Avoid:** Using Effects to share logic | |
| ```javascript | |
| // Bad: Effect to share logic | |
| useEffect(() => { | |
| if (isOn) { | |
| document.title = `App is on`; | |
| } else { | |
| document.title = `App is off`; | |
| } | |
| }, [isOn]); | |
| ``` | |
| **✅ Good:** Extract to a function | |
| ```javascript | |
| // Good: Extract to a function | |
| function updatePageTitle(isOn) { | |
| if (isOn) { | |
| document.title = `App is on`; | |
| } else { | |
| document.title = `App is off`; | |
| } | |
| } | |
| function Toggle() { | |
| const [isOn, setIsOn] = useState(false); | |
| function handleToggleClick() { | |
| setIsOn(!isOn); | |
| updatePageTitle(!isOn); | |
| } | |
| // ... | |
| } | |
| ``` | |
| ## Key Takeaways | |
| 1. **If you can calculate something during render, you don't need an Effect.** | |
| 2. **To cache expensive calculations, add `useMemo` instead of `useEffect`.** | |
| 3. **To reset the state of an entire component tree, pass a different `key` to it.** | |
| 4. **To reset a particular bit of state in response to a prop change, set it during rendering.** | |
| 5. **Code that runs because a component was displayed should be in Effects, the rest should be in events.** | |
| 6. **If you need to update the state of several components, it's better to do it during a single event.** | |
| 7. **Whenever you try to synchronize state variables in different components, consider lifting state up.** | |
| 8. **You can fetch data with Effects, but you need to implement cleanup to avoid race conditions.** | |
| ## Modern Alternatives | |
| - **React Compiler:** Automatically memoizes expensive calculations | |
| - **Modern frameworks:** Provide more efficient built-in data fetching mechanisms | |
| - **Custom hooks:** Extract reusable logic with declarative APIs | |
| ## Reference | |
| This summary is based on the official React documentation: [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment