React: useEffect ودورة حياة التطبيق

آخر تحديث: 2026-08-26

إذا كان useState هو «ذاكرة» المكون، فإن useEffect هو «الكاميرا» الخاصة به — فهو يتيح لك القيام ببعض الأمور الإضافية بعد عرض المكون على الشاشة («بعد التقاط الصورة»): طلب البيانات، والاشتراك في الأحداث، والتعديل على DOM، وضبط المؤقتات.


1. ما ستتعلمه



2. قصة صفحة تحميل البيانات

(1) المشكلة: طلبات البيانات تتسبب في حلقة لا نهائية

تريد أليس طلب بيانات المستخدم عند تحميل المكون، لذا كتبت ما يلي:

JSX
function UserProfile({ userId }) {
  const [user, setUser] = React.useState(null)

  // ❌ Error:Requesting data directly within a component's function body
  fetch('/api/users/' + userId)
    .then(res => res.json())
    .then(data => setUser(data))

  return <div>{user?.name}</div>
}
▶ جرّب الكود

السؤال:

  1. fetchsetUser(data) → إعادة عرض المكون
  2. إعادة العرض → تنفيذ fetch مرة أخرى → إعادة تعيين الحالة → إعادة العرض...
  3. حلقة لا نهائية! الصفحة متوقفة.

تحتاج أليس إلى طريقة لـ «التنفيذ مرة واحدة فقط عند تركيب المكون».

(2) حل useEffect

JSX
import { useState, useEffect } from 'react'

function UserProfile({ userId }) {
  const [user, setUser] = useState(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)

  // ✅ Correct:useEffect + Empty array of dependencies
  useEffect(() => {
    fetch('/api/users/' + userId)
      .then(res => {
        if (!res.ok) throw new Error('Failed to load')
        return res.json()
      })
      .then(data => {
        setUser(data)
        setLoading(false)
      })
      .catch(err => {
        setError(err.message)
        setLoading(false)
      })
  }, [userId])  // Only at userId Re-execute when changes occur

  if (loading) return <p>Loading......</p>
  if (error) return <p>Error:{error}</p>
  return <h1>{user.name}</h1>
}
▶ جرّب الكود

المزايا: useEffect يفصل الآثار الجانبية عن منطق العرض — حيث يقتصر دور العرض على واجهة المستخدم فقط، بينما يتم تنفيذ الآثار الجانبية بعد اكتمال عملية العرض.



3. أساسيات useEffect

(1) قواعد النحو الأساسية

JSX
useEffect(() => {
  // Side Effect Logic(Execute after rendering is complete)
  console.log('Component rendering complete!')
  
  return () => {
    // Cleanup Function(Run before unloading or re-executing a component)
    console.log('Addressing Side Effects')
  }
}, [Dependency Array])
▶ جرّب الكود
القسم الوصف
() => { ... } استدعاء رد الفعل الجانبي، الذي يتم تنفيذه بعد إتمام عرض المحتوى على الشاشة
return () => { ... } وظيفة التنظيف؛ تُنفَّذ قبل إعادة التنفيذ نتيجة لإلغاء تثبيت أحد المكونات أو تغييرات في التبعيات
[dependencies] مصفوفة تتحكم في توقيت إعادة تشغيل useEffect
100%
graph TB
    A[Component Rendering] --> B[React Submit DOM Update]
    B --> C[useEffect Callback Execution]
    C --> D{Changes in Dependencies?}
    D -->|is | E[Execute the previous cleanup function]
    E --> F[Re-execute useEffect]
    D -->|No| G[Skip]
    F --> H{Component Uninstallation?}
    G --> H
    H -->|is | I[Execute the cleanup function]
    
    style C fill:#61dafb,color:#000
    style I fill:#ff6b6b,color:#fff

(2) ثلاثة أنماط لمصفوفات التبعية

JSX
// Pattern 1:Empty array [] — Execute only once when mounted
useEffect(() => {
  console.log('Component Mounting')
  fetch('/api/init').then(setData)
}, [])  // Never re-execute

// Pattern 2:Dependencies [a, b] — Re-execute when dependencies change
useEffect(() => {
  console.log('userId It has changed.:', userId)
  fetch('/api/users/' + userId).then(setUser)
}, [userId])  // userId Re-execute when changes occur

// Pattern 3:No array dependencies — Executed on every render
useEffect(() => {
  console.log('Executed on every render')
})  // Note:No array!
▶ جرّب الكود
مجموعة التبعيات توقيت التنفيذ حالات الاستخدام
[] مرة واحدة فقط عند التثبيت تهيئة طلبات البيانات والاشتراكات
[dep1, dep2] عند التثبيت + عند تغير التبعيات تغير البيانات مع المعلمات
مجموعات لا حصر لها بعد كل عملية عرض نادرًا ما تُستخدم (عادةً ما تُستبدل بطرق أخرى)


4. وظائف التنظيف

تعد وظائف التنظيف أساسية لمنع تسربات الذاكرة وحالات التنافس.

(1) مسح المؤقت

JSX
function Timer() {
  const [seconds, setSeconds] = useState(0)

  useEffect(() => {
    const timer = setInterval(() => {
      setSeconds(s => s + 1)
    }, 1000)

    // ✅ Clear the timer when the component is unloaded
    return () => {
      clearInterval(timer)
      console.log('The timer has been cleared.')
    }
  }, [])  // Start only when mounted

  return <p>Running: {seconds}s</p>
}
// If you don't clean it,:The timer continues to run even after the component is unloaded,Error "Update on unmounted components"
▶ جرّب الكود

(2) تنظيف مستمعي الأحداث

JSX
function WindowSize() {
  const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight })

  useEffect(() => {
    function handleResize() {
      setSize({ width: window.innerWidth, height: window.innerHeight })
    }

    window.addEventListener('resize', handleResize)

    // ✅ Remove event listeners when the component is unmounted
    return () => {
      window.removeEventListener('resize', handleResize)
    }
  }, [])

  return <p>Window:{size.width} × {size.height}</p>
}
▶ جرّب الكود

(3) طلب الإلغاء (لتجنب حالات التنافس)

JSX
function SearchResults({ query }) {
  const [results, setResults] = useState([])

  useEffect(() => {
    let cancelled = false

    fetch('/api/search?q=' + query)
      .then(res => res.json())
      .then(data => {
        // ✅ If the component has been uninstalled or query Has changed,Do not update status
        if (!cancelled) {
          setResults(data)
        }
      })

    // ✅ Cleanup:Uncheck
    return () => {
      cancelled = true
    }
  }, [query])

  return <div>{results.map(r => <p key={r.id}>{r.name}</p>)}</div>
}
// When users quickly switch search terms:
// 1. Search"A" → useEffect Execute
// 2. Search"AB" → Clear Function Markers cancelled=true → useEffect Re-execute
// 3. Search"A" the response came back → cancelled=true → Do not update status(Avoid flashing) 
▶ جرّب الكود

▶ مثال: شرح شامل لوظائف التنظيف

JSX 📖 للعرض فقط
// ============================================
// Example:useEffect Declaration Cycle Demonstration
// Features:Start the timer when mounted + Listening for Keyboard Events
//       Clean up all resources upon uninstallation
// ============================================

function LifecycleDemo() {
  const [count, setCount] = useState(0)
  const [logs, setLogs] = useState([])

  // Effect 1:Title Update
  useEffect(() => {
    document.title = `Count:${count}`
  }, [count])

  // Effect 2:Timer
  useEffect(() => {
    const id = setInterval(() => {
      setCount(c => c + 1)
    }, 2000)

    addLog('⏱️ The timer has started')

    return () => {
      clearInterval(id)
      addLog('⏱️ The timer has been cleared.')
    }
  }, [])

  // Effect 3:Keyboard Events
  useEffect(() => {
    function handleKey(e) {
      if (e.key === ' ') {
        setCount(c => c + 5)
      }
    }
    window.addEventListener('keydown', handleKey)

    return () => {
      window.removeEventListener('keydown', handleKey)
      addLog('⌨️ Keyboard listening has been removed')
    }
  }, [])

  function addLog(msg) {
    setLogs(prev => [...prev, `${new Date().toLocaleTimeString()} ${msg}`])
  }

  return (
    <div>
      <h2>useEffect Life Cycle Demonstration</h2>
      <p>Count:{count} (+1 every 2s, Space +5)</p>
      <div style={{ maxHeight: '200px', overflow: 'auto', backgroundColor: '#f5f5f5', padding: '10px', borderRadius: '4px', fontSize: '12px', fontFamily: 'monospace' }}>
        {logs.map((log, i) => <div key={i}>{log}</div>)}
      </div>
    </div>
  )
}
41 سطر من الكود المنطقي (تجاوز الحد 40, للعرض فقط)

5. ربط useEffect بدورة حياة المكون

في عصر مكونات الفئات، كان هناك ثلاثة «هوكات» لدورة الحياة؛ أما في عصر «الهوكات»، useEffect—فإن «هوك» واحدًا يؤدي عمل ثلاثة:

100%
graph LR
    subgraph "The Lifecycle of Class Components"
        A1[componentDidMount] --> A2[componentDidUpdate]
        A2 --> A3[componentWillUnmount]
    end
    
    subgraph "Hooks 's  useEffect"
        B1["useEffect(fn, [])<br/>Execute when mounted"] 
        B2["useEffect(fn, [dep])<br/>Mount + run when deps change"]
        B3["return cleanup<br/>Clean up before uninstalling or rerunning"]
    end
دورة حياة مكونات الفئة useEffect المقابل
componentDidMount useEffect(() => { ... }, [])
componentDidUpdate useEffect(() => { ... }) (مجموعات لا حصر لها) أو useEffect(() => { ... }, [dep])
وظائف التنظيف في componentWillUnmount useEffect(() => { return () => { ... } }, [])

▶ مثال: استخدام useEffect واحد للتعامل مع مراحل متعددة من دورة الحياة

JSX
// ============================================
// Example:Chat Room Component——One useEffect Covering the Entire Lifecycle
// ============================================

function ChatRoom({ roomId }) {
  const [messages, setMessages] = useState([])

  useEffect(() => {
    // === componentDidMount + componentDidUpdate ===
    console.log(`🟢 Connect to the chat room:${roomId}`)
    const connection = createConnection(roomId)
    connection.connect()

    connection.on('message', (msg) => {
      setMessages(prev => [...prev, msg])
    })

    // === componentWillUnmount + Clean Up Before Re-Execution ===
    return () => {
      console.log(`🔴 Leave the chat room:${roomId}`)
      connection.disconnect()
    }
  }, [roomId])  // roomId When things change:Disconnect the old connection → Join a New Chat Room

  return (
    <div>
      <h3>Chat Room:{roomId}</h3>
      {messages.map((msg, i) => <p key={i}>{msg}</p>}
    </div>
  )
}

// Usage
<ChatRoom roomId="general" />     // Connect general Chat Room
<ChatRoom roomId="random" />      // roomId Changes → Disconnect general → Connect random
// When a component is unloaded → Disconnect the current connection(Execution of the cleanup function)
▶ جرّب الكود

6. useEffect مقابل useLayoutEffect

يوفر React خطافين من نوع «الآثار الجانبية»، يختلفان من حيث توقيت التنفيذ.

100%
graph LR
    A[Trigger Rendering] --> B[Computational Virtual DOM]
    B --> C[DOM Update]
    C --> D{useLayoutEffect?}
    D -->|is | E[Execute in parallel<br/>Blocking Browser Rendering]
    D -->|No| F[Browser rendering complete]
    F --> G[useEffect Asynchronous Execution]
    
    style E fill:#faad14,color:#000
    style G fill:#52c41a,color:#fff
الخطاف توقيت التنفيذ يعيق عملية العرض حالات الاستخدام
useEffect بعد عرض المتصفح (بشكل غير متزامن) 90% من الحالات: طلبات البيانات، مستمعو الأحداث، التسجيل
useLayoutEffect بعد تحديثات DOM، قبل عرض المتصفح (متزامن) قياس أبعاد DOM، وقراءة التخطيط، ومزامنة الرسوم المتحركة
JSX
import { useState, useEffect, useLayoutEffect } from 'react'

function MeasureExample() {
  const [width, setWidth] = useState(0)
  const ref = useRef(null)

  // ❌ useEffect Read DOM Dimensions → Users may notice flickering
  useEffect(() => {
    setWidth(ref.current.offsetWidth)  // Read After Drawing → May trigger additional rendering
  }, [])

  // ✅ useLayoutEffect → Read Before Drawing,Transparent to the user
  useLayoutEffect(() => {
    setWidth(ref.current.offsetWidth)
  }, [])

  return <div ref={ref}>Width:{width}px</div>
}
▶ جرّب الكود

القواعد: ابدأ بكتابة useEffect؛ ولا تنتقل إلى useLayoutEffect إلا إذا واجهت مشكلات تتعلق بـ«الوميض» أو «تذبذب التخطيط».



7. مثال كامل: لوحة بيانات

JSX
// ============================================
// Complete Example:Data Dashboard(useEffect Integrated Applications)
// Features:Refresh data at regular intervals + Window Adaptation + Resource Cleanup
// ============================================

import { useState, useEffect } from 'react'

function Dashboard() {
  const [data, setData] = useState(null)
  const [isLive, setIsLive] = useState(true)
  const [lastUpdate, setLastUpdate] = useState(null)
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight
  })

  // Effect 1:First Load + Refresh at set intervals
  useEffect(() => {
    function fetchData() {
      // Simulation API Request
      const mockData = {
        users: Math.floor(Math.random() * 1000) + 500,
        orders: Math.floor(Math.random() * 200) + 100,
        revenue: Math.floor(Math.random() * 50000) + 10000,
        growth: (Math.random() * 20 - 5).toFixed(1)
      }
      setData(mockData)
      setLastUpdate(new Date().toLocaleTimeString())
    }

    // Execute once immediately
    fetchData()

    // Refresh at set intervals
    let interval
    if (isLive) {
      interval = setInterval(fetchData, 5000)
    }

    return () => {
      clearInterval(interval)
    }
  }, [isLive])  // isLive Reset the timer when a change occurs

  // Effect 2:Window Size Monitoring
  useEffect(() => {
    function handleResize() {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight
      })
    }

    window.addEventListener('resize', handleResize)
    return () => window.removeEventListener('resize', handleResize)
  }, [])

  // Effect 3:Page Title
  useEffect(() => {
    document.title = `Dashboard - ${data ? `${data.users} User` : 'Loading......'}`
  }, [data])

  // Effect 4:Leave Page Prompt
  useEffect(() => {
    function handleBeforeUnload(e) {
      if (isLive) {
        e.preventDefault()
        e.returnValue = ''
      }
    }
    window.addEventListener('beforeunload', handleBeforeUnload)
    return () => window.removeEventListener('beforeunload', handleBeforeUnload)
  }, [isLive])

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
        <h2>📊 Real-Time Dashboard</h2>
        <div>
          <span style={{ color: '#666', fontSize: '14px', marginRight: '12px' }}>
            Window:{windowSize.width}×{windowSize.height}
          </span>
          <label>
            <input type="checkbox" checked={isLive} onChange={e => setIsLive(e.target.checked)} />
            Refreshes in real time
          </label>
        </div>
      </div>

      {!data ? (
        <p style={{ textAlign: 'center', padding: '40px', color: '#999' }}>
          ⏳ Loading......
        </p>
      ) : (
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '16px' }}>
          <StatCard label="Total Users" value={data.users.toLocaleString()} color="#1890ff" />
          <StatCard label="Today's Orders" value={data.orders.toLocaleString()} color="#52c41a" />
          <StatCard label="Monthly Income" value={`$${data.revenue.toLocaleString()}`} color="#ff4d4f" />
          <StatCard label="Growth Rate" value={`${data.growth}%`} color={parseFloat(data.growth) >= 0 ? '#52c41a' : '#ff4d4f'} />
        </div>
      )}

      <p style={{ textAlign: 'right', color: '#999', fontSize: '12px', marginTop: '12px' }}>
        Last Updated:{lastUpdate} {isLive ? '(Auto-refresh every 5s)' : '(Suspended)'}
      </p>
    </div>
  )
}

function StatCard({ label, value, color }) {
  return (
    <div style={{
      border: '1px solid #f0f0f0',
      borderRadius: '8px',
      padding: '20px',
      textAlign: 'center',
      boxShadow: '0 2px 4px rgba(0,0,0,0.05)'
    }}>
      <p style={{ color: '#666', margin: '0 0 8px 0' }}>{label}</p>
      <p style={{ fontSize: '28px', fontWeight: 'bold', color, margin: 0 }}>{value}</p>
    </div>
  )
}

الناتج المتوقع: لوحة بيانات تحتوي على 4 بطاقات إحصائية، ومفتاح لتحديث البيانات في الوقت الفعلي، ومؤشر لحجم النافذة، ووقت آخر تحديث.


▶ المثال 3: استخدام useEffect لتنفيذ مزامنة البيانات في الوقت الفعلي

JSX
function LiveSearch({ apiBase }) {
  const [query, setQuery] = useState('')
  const [results, setResults] = useState([])
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    if (!query.trim()) { setResults([]); return }
    setLoading(true)
    const controller = new AbortController()
    fetch(`${apiBase}/search?q=${encodeURIComponent(query)}`, { signal: controller.signal })
      .then(res => res.json())
      .then(data => { setResults(data); setLoading(false) })
      .catch(err => { if (err.name !== 'AbortError') setLoading(false) })
    return () => controller.abort()
  }, [query, apiBase])

  return (
    <div style={{ maxWidth: 400, margin: '0 auto' }}>
      <input value={query} onChange={e => setQuery(e.target.value)}
        placeholder="Search users..." style={{ width: '100%', padding: 8, borderRadius: 4, marginBottom: 8 }} />
      {loading && <p>Searching...</p>}
      <ul style={{ listStyle: 'none', padding: 0 }}>
        {results.map(r => <li key={r.id} style={{ padding: 4, borderBottom: '1px solid #f0f0f0' }}>{r.name}</li>)}
      </ul>
    </div>
  )
}
▶ جرّب الكود

▶ المثال 4: استخدام useEffect لمراقبة التغييرات في حجم النافذة

JSX
function useWindowSize() {
  const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight })

  useEffect(() => {
    function handleResize() {
      setSize({ width: window.innerWidth, height: window.innerHeight })
    }
    window.addEventListener('resize', handleResize)
    return () => window.removeEventListener('resize', handleResize)
  }, [])

  return size
}

function ResponsiveLayout() {
  const { width } = useWindowSize()
  const layout = width < 640 ? 'mobile' : width < 1024 ? 'tablet' : 'desktop'

  return (
    <div style={{ padding: 16, maxWidth: 600, margin: '0 auto' }}>
      <h3>Viewport: {width}px ({layout})</h3>
      {layout === 'mobile' && <p>📱 Single column layout</p>}
      {layout === 'tablet' && <p>📟 Two column layout</p>}
      {layout === 'desktop' && <p>💻 Three column layout with sidebar</p>}
    </div>
  )
}
▶ جرّب الكود

▶ المثال 5: استخدام useEffect + localStorage للحفاظ على الحالة

JSX
function usePersistedState(key, initial) {
  const [value, setValue] = useState(() => {
    try {
      const saved = localStorage.getItem(key)
      return saved !== null ? JSON.parse(saved) : initial
    } catch { return initial }
  })

  useEffect(() => {
    try { localStorage.setItem(key, JSON.stringify(value)) }
    catch (e) { console.error('Save failed:', e) }
  }, [key, value])

  return [value, setValue]
}

function TodoApp() {
  const [todos, setTodos] = usePersistedState('todos', [])
  const [input, setInput] = useState('')

  function addTodo() {
    if (!input.trim()) return
    setTodos(prev => [...prev, { id: Date.now(), text: input.trim(), done: false }])
    setInput('')
  }

  function toggleTodo(id) {
    setTodos(prev => prev.map(t => t.id === id ? { ...t, done: !t.done } : t))
  }

  return (
    <div style={{ maxWidth: 400, margin: '0 auto' }}>
      <h3>Todos (persisted)</h3>
      <div style={{ display: 'flex', gap: 8, marginBottom: 8 }}>
        <input value={input} onChange={e => setInput(e.target.value)}
          onKeyDown={e => e.key === 'Enter' && addTodo()}
          placeholder="Add task..." style={{ flex: 1, padding: 8, borderRadius: 4 }} />
        <button onClick={addTodo} style={{ padding: '8px 16px', cursor: 'pointer' }}>Add</button>
      </div>
      <ul style={{ listStyle: 'none', padding: 0 }}>
        {todos.map(t => (
          <li key={t.id} onClick={() => toggleTodo(t.id)}
            style={{ padding: 4, cursor: 'pointer', textDecoration: t.done ? 'line-through' : 'none', color: t.done ? '#999' : '#333' }}>
            {t.text}
          </li>
        ))}
      </ul>
    </div>
  )
}


❓ أسئلة شائعة

س ما الفرق بين useEffect وكتابة الكود مباشرةً داخل المكون؟
ج لا يتم تشغيل الكود الموجود داخل useEffect إلا بعد اكتمال عملية العرض، وبالتالي فهو لا يعطل واجهة المستخدم. أما الكود المكتوب مباشرةً داخل جسم دالة المكون فيتم تشغيله أثناء عملية العرض (مما يؤدي إلى تعطيلها) ويتم تنفيذه في كل عملية عرض. والفرق الرئيسي هو أن useEffect يسمح لك بإجراء عملية التنظيف عند إلغاء تثبيت المكون.
س لماذا يتم تشغيل وظيفة التنظيف في useEffect قبل كل عملية إعادة تنفيذ؟
ج هذا ضمان تصميمي في React — فهو يمنع «حالات التنافس» الناتجة عن التغييرات في التبعيات. على سبيل المثال، عندما يتغير userId، يتم تنظيف الطلب القديم قبل بدء طلب جديد، مما يضمن أن البيانات الجديدة تحل محل البيانات القديمة. إذا كان الطلب الجديد سيحل محل القديم مباشرةً، فقد يحدث خطأً يتمثل في «إكمال الطلب القديم أولاً → عودة البيانات إلى حالتها السابقة».
س ما هو ترتيب تنفيذ عدة خطافات useEffect؟
ج يتم تنفيذها بالترتيب الذي تظهر به في الكود. لذلك، يجب وضع خطافات useEffect التي تتولى «التهيئة» (مثل تحميل البيانات) أولاً، وتلك التي تتولى «الاستجابة للتغييرات» (مثل مزامنة الحالة مع localStorage) أخيرًا. أثناء عملية عرض واحدة، يتم تنفيذ جميع خطافات useEffect بالتسلسل.
س ما الفرق بين useEffect وuseLayoutEffect؟
ج يختلفان في توقيت تنفيذهما: يتم تنفيذ useEffect بشكل غير متزامن بعد تحديث DOM (بعد قيام المتصفح بعرض الصفحة)، وبالتالي لن يلاحظ المستخدمون أي وميض؛ أما useLayoutEffect فيُنفَّذ بشكل متزامن بعد تحديث DOM (قبل أن يقوم المتصفح بعرضه)، مما يتيح لك تعديل DOM ثم جعل المتصفح يعرضه. استخدم useEffect في 99% من الحالات. استخدم useLayoutEffect فقط عندما «تحتاج إلى إجراء حسابات بناءً على تخطيط DOM ثم تعديل DOM بشكل متزامن» (مثل تعديل موضع عنصر ما بعد قياس أبعاده).

📖 ملخص


📝 تمارين

  1. المشكلة الأساسية (صعوبة ⭐): أنشئ مكونًا باسم PageTitle. استخدم useEffect لتغيير عنوان الصفحة إلى "مرحبًا بكم في موقعي الإلكتروني" عند تثبيت المكون، وإعادة العنوان إلى ما كان عليه عند إلغاء تثبيته.
  2. تمرين متقدم (مستوى الصعوبة ⭐⭐): قم بإنشاء مكون OnlineStatus يستخدم useEffect للاستماع إلى الأحداث الواردة من navigator.onLine وonline/offline، وعرض حالة الشبكة في الوقت الفعلي.
  3. التحدي (الصعوبة: ⭐⭐⭐): أنشئ هوكًا مخصصًا باسم usePolling يقبل المعلمات url وinterval، ويقوم باستقصاء الواجهة مرة واحدة كل interval مللي ثانية، ويعيد القيمة { data, isLoading, error }. يجب أن يدعم الهوك إيقاف الاستقصاء مؤقتًا واستئنافه.
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%