|  | 
|  | 1 | +--- | 
|  | 2 | +description:  | 
|  | 3 | +globs: *.tsx,*.jsx | 
|  | 4 | +alwaysApply: false | 
|  | 5 | +--- | 
|  | 6 | +### Avoid useEffect | 
|  | 7 | + | 
|  | 8 | +[You Might Not Need `useEffect`](https://react.dev/learn/you-might-not-need-an-effect) | 
|  | 9 | + | 
|  | 10 | +Instead of using `useEffect`, use ref callbacks, event handlers with | 
|  | 11 | +`flushSync`, css, `useSyncExternalStore`, etc. | 
|  | 12 | + | 
|  | 13 | +```tsx | 
|  | 14 | +// This example was ripped from the docs: | 
|  | 15 | +// ✅ Good | 
|  | 16 | +function ProductPage({ product, addToCart }) { | 
|  | 17 | +	function buyProduct() { | 
|  | 18 | +		addToCart(product) | 
|  | 19 | +		showNotification(`Added ${product.name} to the shopping cart!`) | 
|  | 20 | +	} | 
|  | 21 | + | 
|  | 22 | +	function handleBuyClick() { | 
|  | 23 | +		buyProduct() | 
|  | 24 | +	} | 
|  | 25 | + | 
|  | 26 | +	function handleCheckoutClick() { | 
|  | 27 | +		buyProduct() | 
|  | 28 | +		navigateTo('/checkout') | 
|  | 29 | +	} | 
|  | 30 | +	// ... | 
|  | 31 | +} | 
|  | 32 | + | 
|  | 33 | +useEffect(() => { | 
|  | 34 | +	setCount(count + 1) | 
|  | 35 | +}, [count]) | 
|  | 36 | + | 
|  | 37 | +// ❌ Avoid | 
|  | 38 | +function ProductPage({ product, addToCart }) { | 
|  | 39 | +	useEffect(() => { | 
|  | 40 | +		if (product.isInCart) { | 
|  | 41 | +			showNotification(`Added ${product.name} to the shopping cart!`) | 
|  | 42 | +		} | 
|  | 43 | +	}, [product]) | 
|  | 44 | + | 
|  | 45 | +	function handleBuyClick() { | 
|  | 46 | +		addToCart(product) | 
|  | 47 | +	} | 
|  | 48 | + | 
|  | 49 | +	function handleCheckoutClick() { | 
|  | 50 | +		addToCart(product) | 
|  | 51 | +		navigateTo('/checkout') | 
|  | 52 | +	} | 
|  | 53 | +	// ... | 
|  | 54 | +} | 
|  | 55 | +``` | 
|  | 56 | + | 
|  | 57 | +There are a lot more examples in the docs. `useEffect` is not banned or | 
|  | 58 | +anything. There are just better ways to handle most cases. | 
|  | 59 | + | 
|  | 60 | +Here's an example of a situation where `useEffect` is appropriate: | 
|  | 61 | + | 
|  | 62 | +```tsx | 
|  | 63 | +// ✅ Good | 
|  | 64 | +useEffect(() => { | 
|  | 65 | +	const controller = new AbortController() | 
|  | 66 | + | 
|  | 67 | +	window.addEventListener( | 
|  | 68 | +		'keydown', | 
|  | 69 | +		(event: KeyboardEvent) => { | 
|  | 70 | +			if (event.key !== 'Escape') return | 
|  | 71 | + | 
|  | 72 | +			// do something based on escape key being pressed | 
|  | 73 | +		}, | 
|  | 74 | +		{ signal: controller.signal }, | 
|  | 75 | +	) | 
|  | 76 | + | 
|  | 77 | +	return () => { | 
|  | 78 | +		controller.abort() | 
|  | 79 | +	} | 
|  | 80 | +}, []) | 
|  | 81 | +``` | 
0 commit comments