إدارة الحالة المتقدمة باستخدام useReducer

الدرس السابع عشر: إدارة الحالة المتقدمة باستخدام useReducer

في هذا الدرس، سنتعرف على useReducer، وهو React Hook يُستخدم لإدارة الحالة في المكونات، خاصة عندما تكون الحالة معقدة أو تتطلب تغييرات متعددة تعتمد على نوع من الأحداث. سنتعرف على الفرق بين useState و useReducer، وكيفية استخدام useReducer لإدارة الحالة المتقدمة، وسنقوم بتطبيق useReducer لإدارة حالة تطبيق يحتوي على عمليات متعددة.

1. الفرق بين useState و useReducer

useState:

  • useState هو React Hook يُستخدم لإدارة الحالة البسيطة، مثل الأرقام أو النصوص أو القيم المنطقية (boolean). يتم استخدامه عادةً عند التعامل مع حالات قليلة التغيير.
  • useState مثالي عندما يكون لديك حالة واحدة أو حالتان بسيطتان ولا تحتاج إلى منطق معقد لتغيير الحالة.

useReducer:

  • useReducer هو React Hook يُستخدم لإدارة الحالات الأكثر تعقيدًا التي تتطلب تحديثات متعددة بناءً على أنواع مختلفة من الأحداث.
  • يُفضل استخدام useReducer عندما تكون الحالة تحتوي على كائنات أو مصفوفات معقدة أو تحتاج إلى منطق متقدم لتحديثها.
  • يعمل useReducer بشكل مشابه لـ Redux في إدارة الحالة، حيث يتم تمرير الـ reducer (دالة تُعالج التحديثات) وأحداث dispatch لتحديث الحالة بناءً على نوع الحدث.

2. كيفية استخدام useReducer لإدارة الحالة المعقدة

الهيكل الأساسي لاستخدام useReducer:

useReducer يتطلب ثلاثة أشياء أساسية:

  1. reducer: دالة تُحدِّث الحالة بناءً على الحدث.
  2. initialState: الحالة الأولية (التفاصيل التي تبدأ منها الحالة).
  3. dispatch: دالة تُستخدم لإرسال الأحداث إلى الـ reducer لتحديث الحالة.

مثال على استخدام useReducer:

import React, { useReducer } from 'react';

// الحالة الأولية
const initialState = { count: 0 };

// دالة الـ reducer
function counterReducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'reset':
      return { count: 0 };
    default:
      return state;
  }
}

function Counter() {
  // استخدام useReducer
  const [state, dispatch] = useReducer(counterReducer, initialState);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
      <button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
    </div>
  );
}

export default Counter;

الشرح:

  • counterReducer هو الدالة المسؤولة عن تحديث الحالة بناءً على action.type.
  • عند الضغط على الأزرار، نقوم بإرسال action مع type معين باستخدام dispatch.
  • useReducer يعيد الحالة الحالية (state) ودالة dispatch التي تستخدم لإرسال الأحداث.

3. تطبيق useReducer لإدارة حالة تطبيق متعدد العمليات

في بعض التطبيقات التي تحتوي على حالات معقدة تتطلب تحديثات متعددة أو تعتمد على عمليات مختلفة، يمكن أن يكون useReducer الخيار الأمثل. لنأخذ مثالًا على تطبيق يحتوي على عمليات متعددة مثل إضافة عنصر إلى قائمة، إزالة عنصر، وتحديث العنصر.

مثال تطبيقي باستخدام useReducer:

import React, { useReducer } from 'react';

// الحالة الأولية
const initialState = {
  items: [],
  loading: false,
  error: null,
};

// دالة الـ reducer
function appReducer(state, action) {
  switch (action.type) {
    case 'ADD_ITEM':
      return { ...state, items: [...state.items, action.payload] };
    case 'REMOVE_ITEM':
      return { ...state, items: state.items.filter(item => item.id !== action.payload.id) };
    case 'TOGGLE_LOADING':
      return { ...state, loading: !state.loading };
    case 'SET_ERROR':
      return { ...state, error: action.payload };
    default:
      return state;
  }
}

function App() {
  const [state, dispatch] = useReducer(appReducer, initialState);

  const addItem = (item) => {
    dispatch({ type: 'ADD_ITEM', payload: item });
  };

  const removeItem = (id) => {
    dispatch({ type: 'REMOVE_ITEM', payload: { id } });
  };

  const toggleLoading = () => {
    dispatch({ type: 'TOGGLE_LOADING' });
  };

  return (
    <div>
      <button onClick={toggleLoading}>
        {state.loading ? 'Stop Loading' : 'Start Loading'}
      </button>
      <div>
        {state.loading && <p>Loading...</p>}
        {state.error && <p>Error: {state.error}</p>}
        <ul>
          {state.items.map(item => (
            <li key={item.id}>
              {item.name}
              <button onClick={() => removeItem(item.id)}>Remove</button>
            </li>
          ))}
        </ul>
      </div>
      <button onClick={() => addItem({ id: Date.now(), name: 'New Item' })}>
        Add Item
      </button>
    </div>
  );
}

export default App;

الشرح:

  • appReducer يعالج أربعة أنواع من الأحداث: إضافة عنصر، إزالة عنصر، التبديل بين حالة التحميل، وتعيين خطأ.
  • كل عملية (إضافة، إزالة، تغيير حالة التحميل، تعيين الخطأ) يتم التعامل معها عن طريق dispatch مع نوع الحدث المناسب.
  • useReducer يعيد الحالة الحالية ويقوم بتحديث واجهة المستخدم بناءً على التغييرات في هذه الحالة.

4. متى يجب استخدام useReducer؟

يعتبر useReducer مفيدًا في الحالات التي:

  • تحتاج فيها إلى تحديثات معقدة لحالة تعتمد على عدة إجراءات أو متغيرات.
  • عندما تكون state عبارة عن كائن أو مصفوفة تحتوي على بيانات متعددة.
  • عندما تحتاج إلى التعامل مع حالات متعددة أو منطق معقد داخل reducer.

5. الختام

useReducer هو طريقة قوية لإدارة الحالة في React، خاصة عندما تكون لديك حالات معقدة أو متغيرات متعددة تحتاج إلى تحديثها بناءً على أنواع مختلفة من الأحداث. مقارنة بـ useState، useReducer يوفر حلاً أكثر هيكلية ومرونة لإدارة حالات أكبر وأكثر تعقيدًا.


اكتشاف المزيد من كود التطور

اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.

اترك رد

Scroll to Top