Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
LoginSign Up
menu
  1. Home
  2. /Web Development
  3. /React
  4. /Dependency Arrays
Your Progress0%
0 of 42 completed

React Topics

Getting Started

  • What is React?
  • React vs Vanilla JavaScript
  • Setting Up Your Environment
  • Your First React App

JSX Fundamentals

  • Introduction to JSX
  • JSX Expressions and Variables
  • Conditional Rendering
  • Lists and Keys
  • Styling in JSX

Components Basics

  • Function Components
  • Props
  • Children Prop
  • Props Destructuring
  • Component Composition

State Management

  • Introduction to State
  • useState Hook
  • State Updates and Re-renders
  • Multiple State Variables
  • State Best Practices

Events and Interactivity

  • Handling Events
  • Event Objects
  • Forms in React
  • Form Validation

Side Effects and Data

  • Introduction to useEffect
  • Data Fetching
  • Cleanup Functions
  • Dependency Arrays

Advanced Hooks

  • useRef Hook
  • useContext Hook
  • useMemo Hook
  • useCallback Hook

React Patterns

  • Custom Hooks
  • Higher-Order Components
  • Render Props Pattern

React Router

  • Introduction to React Router
  • Routes and Navigation
  • Dynamic Routes and Parameters

Best Practices

  • Component Organization
  • Performance Optimization
  • Error Handling
  • Testing React Components

Real World Project

  • Building a Complete App

Dependency Arrays

Controlling when effects run

The dependency array is one of the most important concepts in React hooks - and one of the most confusing for beginners. It controls when your effects run, and getting it wrong leads to bugs, infinite loops, and stale data. In this lesson, you'll learn exactly how dependency arrays work, what to include, common mistakes to avoid, and how to use them to write efficient, bug-free React code. Let's master dependencies! šŸŽÆ

What Are Dependencies?

Dependencies are values that your effect depends on to work correctly:

dependencies-basic.jsx
function UserProfile({ userId }) {
  const [user, setUser] = React.useState(null)
  
  React.useEffect(() => {
    // This effect DEPENDS ON userId
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => setUser(data))
  }, [userId])  // userId is a dependency
  
  return <div>{user?.name}</div>
}

// Why is userId a dependency?
// Because the effect uses userId to fetch the right user.
// If userId changes, effect needs to re-run with new value.

The Dependency Rule:

Every value from the component scope that's used inside the effect must be in the dependency array. This includes:
• Props
• State variables
• Functions defined in the component
• Variables declared in the component

Three Forms of Dependency Arrays

1. No Array - Runs After Every Render

deps-no-array.jsx
function Component() {
  const [count, setCount] = React.useState(0)
  const [name, setName] = React.useState('')
  
  React.useEffect(() => {
    console.log('Effect ran!')
    document.title = `Count: ${count}, Name: ${name}`
  })  // No dependency array
  
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Count: {count}</button>
      <input value={name} onChange={e => setName(e.target.value)} />
    </div>
  )
}

// Effect runs:
// - After initial render
// - After EVERY re-render (any state/prop change)

// When to use:
// - When you need to sync with something on every render
// - Example: Updating document title based on current state

// Usually you want more control than this!

2. Empty Array [] - Runs Once on Mount

deps-empty-array.jsx
function Component() {
  const [data, setData] = React.useState(null)
  
  React.useEffect(() => {
    console.log('Effect ran!')
    fetch('/api/initial-data')
      .then(res => res.json())
      .then(data => setData(data))
  }, [])  // Empty dependency array
  
  return <div>{data?.name}</div>
}

// Effect runs:
// - After initial render
// - NEVER runs again!

// When to use:
// - Setup that should happen once (initialize, subscribe)
// - Fetching initial data that doesn't depend on props/state
// - Adding event listeners that don't change

// Common for "component did mount" behavior

3. With Dependencies - Runs When Dependencies Change

deps-with-values.jsx
function SearchResults({ query, sortBy }) {
  const [results, setResults] = React.useState([])
  
  React.useEffect(() => {
    console.log('Effect ran!')
    fetch(`/api/search?q=${query}&sort=${sortBy}`)
      .then(res => res.json())
      .then(data => setResults(data))
  }, [query, sortBy])  // Dependencies
  
  return (
    <ul>
      {results.map(item => <li key={item.id}>{item.name}</li>)}
    </ul>
  )
}

// Effect runs:
// - After initial render
// - When query changes
// - When sortBy changes
// - NOT when other things change (other state/props)

// When to use:
// - When effect depends on specific values
// - Most common form!

What to Include in Dependencies

āœ… DO Include These:

Props

include-props.jsx
function Component({ userId, filter }) {
  React.useEffect(() => {
    fetchUserData(userId, filter)  // Uses props
  }, [userId, filter])  // āœ… Include both props
}

State Variables

include-state.jsx
function Component() {
  const [count, setCount] = React.useState(0)
  const [multiplier, setMultiplier] = React.useState(2)
  
  React.useEffect(() => {
    const result = count * multiplier  // Uses state
    console.log(result)
  }, [count, multiplier])  // āœ… Include both state variables
}

Functions Defined in Component

include-functions.jsx
function Component({ userId }) {
  const [user, setUser] = React.useState(null)
  
  const fetchUser = () => {
    fetch(`/api/users/${userId}`)  // Uses userId prop
      .then(res => res.json())
      .then(data => setUser(data))
  }
  
  React.useEffect(() => {
    fetchUser()  // Calls function
  }, [fetchUser])  // āœ… Include function
  
  // Problem: fetchUser is recreated every render!
  // See "Functions as Dependencies" section below for solution
}

āŒ DON'T Include These:

State Setters

exclude-setters.jsx
function Component() {
  const [count, setCount] = React.useState(0)
  
  React.useEffect(() => {
    setCount(prev => prev + 1)
  }, [])  // āŒ DON'T include setCount - it's stable
  
  // State setters never change identity
  // React guarantees they're stable across renders

Constants/Literals

exclude-constants.jsx
const API_URL = 'https://api.example.com'

function Component() {
  React.useEffect(() => {
    fetch(API_URL)
  }, [])  // āŒ DON'T include API_URL - it never changes
  
  // Constants defined outside component never change

Ref Values

exclude-refs.jsx
function Component() {
  const ref = React.useRef(null)
  
  React.useEffect(() => {
    ref.current.focus()
  }, [])  // āŒ DON'T include ref - it's stable
  
  // The ref object itself never changes
  // (ref.current can change, but ref can't)

Common Dependency Mistakes

1. Missing Dependencies - Stale Data

mistake-missing-deps.jsx
// āŒ Wrong - Missing dependency
function Component({ userId }) {
  const [user, setUser] = React.useState(null)
  
  React.useEffect(() => {
    fetch(`/api/users/${userId}`)  // Uses userId
      .then(res => res.json())
      .then(data => setUser(data))
  }, [])  // āŒ Missing userId!
  
  return <div>{user?.name}</div>
}

// Problem:
// 1. Component renders with userId = 1, fetches user 1
// 2. userId prop changes to 2
// 3. Effect doesn't re-run (empty array)
// 4. Still showing user 1 data!

// āœ… Correct - Include userId
React.useEffect(() => {
  fetch(`/api/users/${userId}`)
    .then(res => res.json())
    .then(data => setUser(data))
}, [userId])  // āœ… Include userId

2. Object/Array Dependencies - Infinite Loop

mistake-object-deps.jsx
// āŒ Wrong - Infinite loop!
function Component() {
  const [user, setUser] = React.useState(null)
  
  const options = { method: 'GET' }  // New object every render!
  
  React.useEffect(() => {
    fetch('/api/user', options)
      .then(res => res.json())
      .then(data => setUser(data))
  }, [options])  // āŒ options is always "different"!
}

// Problem:
// 1. Component renders, creates new options object
// 2. Effect runs because options changed
// 3. setUser causes re-render
// 4. New options object created
// 5. Effect runs again... infinite loop!

// āœ… Solution 1: Move object inside effect
React.useEffect(() => {
  const options = { method: 'GET' }
  fetch('/api/user', options)
}, [])

// āœ… Solution 2: Use useMemo (advanced)
const options = React.useMemo(() => ({ method: 'GET' }), [])

// āœ… Solution 3: Move outside component
const OPTIONS = { method: 'GET' }
function Component() {
  React.useEffect(() => {
    fetch('/api/user', OPTIONS)
  }, [])

3. State in Dependencies - Infinite Loop

mistake-state-loop.jsx
// āŒ Wrong - Infinite loop!
function Component() {
  const [data, setData] = React.useState([])
  
  React.useEffect(() => {
    setData([...data, 'new item'])  // Updates data
  }, [data])  // āŒ data in dependencies!
}

// Problem:
// 1. Effect runs, updates data
// 2. data changes, effect runs again
// 3. data changes, effect runs again
// 4. Infinite loop!

// āœ… Solution: Use functional update
React.useEffect(() => {
  setData(prev => [...prev, 'new item'])
}, [])  // Remove data from dependencies

4. Functions as Dependencies

mistake-function-deps.jsx
// āŒ Problem - Function recreated every render
function Component({ userId }) {
  const fetchUser = () => {
    fetch(`/api/users/${userId}`)
  }
  
  React.useEffect(() => {
    fetchUser()
  }, [fetchUser])  // fetchUser is new every render!
}

// Problem: fetchUser is a new function every render,
// so effect runs every render

// āœ… Solution 1: Move function inside effect
React.useEffect(() => {
  const fetchUser = () => {
    fetch(`/api/users/${userId}`)
  }
  fetchUser()
}, [userId])

// āœ… Solution 2: Use useCallback (advanced)
const fetchUser = React.useCallback(() => {
  fetch(`/api/users/${userId}`)
}, [userId])

React.useEffect(() => {
  fetchUser()
}, [fetchUser])

Interactive Demo

ReactPlayground.jsx
Code Editor
Preview

šŸ’” Tip: Edit the code above and click "Run" to see your changes

ESLint Plugin for Dependencies

React has an ESLint plugin that warns about dependency mistakes:

install-eslint.sh
# Install the plugin
npm install eslint-plugin-react-hooks --save-dev

# Add to .eslintrc.js
{
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/exhaustive-deps": "warn"
  }
}

The plugin will warn you when:

  • You're missing dependencies
  • You have unnecessary dependencies
  • You're creating infinite loops

āœ… Trust the Linter

The exhaustive-deps rule is very smart!

When it warns about missing dependencies, it's usually right.

Don't disable the warning without understanding why!

Missing dependencies lead to bugs with stale data.

Optimization Patterns

Pattern 1: Extract Static Values

optimize-static.jsx
// āŒ Before - Object created every render
function Component() {
  const options = { method: 'GET', headers: {} }
  
  React.useEffect(() => {
    fetch('/api/data', options)
  }, [options])  // New object every render!
}

// āœ… After - Move outside component
const OPTIONS = { method: 'GET', headers: {} }

function Component() {
  React.useEffect(() => {
    fetch('/api/data', OPTIONS)
  }, [])  // OPTIONS never changes
}

Pattern 2: Move Logic Inside Effect

optimize-inside.jsx
// āŒ Before - Function as dependency
function Component({ userId }) {
  const fetchUser = () => fetch(`/api/users/${userId}`)
  
  React.useEffect(() => {
    fetchUser()
  }, [fetchUser])  // fetchUser is new every render
}

// āœ… After - Move inside effect
function Component({ userId }) {
  React.useEffect(() => {
    const fetchUser = () => fetch(`/api/users/${userId}`)
    fetchUser()
  }, [userId])  // Only userId as dependency
}

Pattern 3: Use Functional Updates

optimize-functional.jsx
// āŒ Before - State as dependency
function Component() {
  const [count, setCount] = React.useState(0)
  
  React.useEffect(() => {
    const id = setInterval(() => {
      setCount(count + 1)  // Uses count
    }, 1000)
    return () => clearInterval(id)
  }, [count])  // Re-runs every second!
}

// āœ… After - Functional update
function Component() {
  const [count, setCount] = React.useState(0)
  
  React.useEffect(() => {
    const id = setInterval(() => {
      setCount(prev => prev + 1)  // Doesn't use count
    }, 1000)
    return () => clearInterval(id)
  }, [])  // Runs once!
}

Key Takeaways

  • Dependency array controls when effects run
  • No array = runs after every render
  • Empty [] = runs once on mount
  • [dependencies] = runs when dependencies change
  • Include all values used in effect from component scope
  • Don't include: setState functions, refs, constants
  • Missing dependencies cause stale data bugs
  • Object/array dependencies can cause infinite loops
  • Use functional updates to avoid state dependencies
  • Move functions inside effects when possible
  • Extract static values outside component
  • Use ESLint plugin to catch dependency mistakes
  • React compares dependencies with Object.is()

What's Next?

Congratulations! You've completed the Side Effects and Data section. You now understand:

  • What side effects are and how to handle them
  • How to fetch data from APIs with useEffect
  • How to clean up effects to prevent memory leaks
  • How to use dependency arrays to control effect execution

You have the foundation for building data-driven React applications that interact with APIs and external systems! But there's still more to learn:

  • Performance Optimization - useMemo, useCallback, React.memo
  • Custom Hooks - Creating reusable logic
  • Context API - Sharing state across components
  • Advanced Patterns - Composition, render props
  • And much more!

Keep building - you're becoming a React expert! šŸŽ‰

Learning how to control useEffect execution with dependency arrays in React!

Previous
Cleanup Functions
Next
useRef Hook

Never Miss a New React Tutorial

Join 2,000+ developers learning React step-by-step. Get new tutorials, tips, and exclusive resources delivered to your inbox - completely FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

React Tutorials

0 of 42 completed

Your Progress0%

Topics

Getting Started

  • What is React?
  • React vs Vanilla JavaScript
  • Setting Up Your Environment
  • Your First React App

JSX Fundamentals

  • Introduction to JSX
  • JSX Expressions and Variables
  • Conditional Rendering
  • Lists and Keys
  • Styling in JSX

Components Basics

  • Function Components
  • Props
  • Children Prop
  • Props Destructuring
  • Component Composition

State Management

  • Introduction to State
  • useState Hook
  • State Updates and Re-renders
  • Multiple State Variables
  • State Best Practices

Events and Interactivity

  • Handling Events
  • Event Objects
  • Forms in React
  • Form Validation

Side Effects and Data

  • Introduction to useEffect
  • Data Fetching
  • Cleanup Functions
  • Dependency Arrays

Advanced Hooks

  • useRef Hook
  • useContext Hook
  • useMemo Hook
  • useCallback Hook

React Patterns

  • Custom Hooks
  • Higher-Order Components
  • Render Props Pattern

React Router

  • Introduction to React Router
  • Routes and Navigation
  • Dynamic Routes and Parameters

Best Practices

  • Component Organization
  • Performance Optimization
  • Error Handling
  • Testing React Components

Real World Project

  • Building a Complete App
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

Ā© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo