استخدام الدالة connect في Redux في تطبيقات React
تُعدّ مكتبة Redux من الأدوات الأكثر شيوعًا لإدارة الحالة في تطبيقات React، إذ توفّر وسيلة مركزية لتخزين الحالة ومشاركتها بين مكونات مختلفة في واجهة المستخدم. إحدى اللبنات الأساسية في الدمج بين React وRedux هي الدالة connect، التي تتيح ربط مكونات React بمخزن الحالة (Redux store) دون أن تحتاج المكونات إلى معرفة تفاصيل آلية التخزين أو بنية الحالة العامة. يُعد استخدام connect خطوة محورية في تسهيل إنشاء تطبيقات متسقة وقابلة للصيانة.
المفهوم الأساسي لـ Redux
قبل التعمق في تفاصيل connect، من المهم أولًا فهم المبادئ التي ترتكز عليها مكتبة Redux. تقوم Redux على ثلاث مبادئ أساسية:
-
مصدر وحيد للحقيقة (Single Source of Truth): يُخزَّن كامل حالة التطبيق في كائن JavaScript واحد داخل “store”.
-
الحالة للقراءة فقط (State is Read-only): لا يمكن تغيير الحالة مباشرة؛ بل يجب إرسال “إجراء” (action) يصف التغيير المطلوب.
-
التغييرات تتم من خلال دوال نقية (Reducers): تُحدد كيفية انتقال الحالة من وضع إلى آخر من خلال دوال تأخذ الحالة الحالية والإجراء كوسيطين وتُعيد الحالة الجديدة.
العلاقة بين React وRedux
تُبنى React على مفهوم المكونات، حيث يقوم كل مكون بعرض واجهة بناءً على الخصائص (props) والحالة (state). ومع نمو التطبيقات وتعقيد العلاقات بين المكونات، تصبح إدارة الحالة المشتركة بين هذه المكونات أكثر صعوبة. هنا تظهر الحاجة إلى مكتبة مثل Redux، لتوفير مكان واحد تُخزَّن فيه الحالة ويمكن لأي مكون الوصول إليها وتحديثها بطريقة منظمة.
لكن React لا تعرف افتراضيًا عن Redux، ولذلك يلزم وجود وسيط يربط بين الطرفين. هذا الوسيط هو مكتبة react-redux، والتي توفّر بدورها الدالة connect.
ما هي الدالة connect؟
الدالة connect هي دالة من مكتبة react-redux تُستخدم لربط مكونات React بمخزن Redux. وهي تعمل كدالة عالية الترتيب (Higher-Order Component) تأخذ مكونًا وتُعيد مكونًا جديدًا متصلًا بـ store.
الشكل العام:
javascriptconnect(mapStateToProps, mapDispatchToProps)(Component)
المعاملات الأساسية:
-
mapStateToProps: دالة تُحدّد أي جزء من حالة Redux يجب تمريره كمُدخلات (props) للمكون. -
mapDispatchToProps: دالة تُحدّد كيف يمكن للمكون إرسال إجراءات (actions) إلى المخزن لتحديث الحالة. -
Component: هو مكون React الذي نريد ربطه بـ Redux.
دالة mapStateToProps
هي دالة اختيارية تُستخدم لاختيار الأجزاء من الحالة العامة للتطبيق التي يحتاجها المكون. تأخذ state من المخزن وتُعيد كائنًا يُضاف إلى الخصائص (props) الخاصة بالمكون.
javascriptconst mapStateToProps = (state) => ({
counter: state.counter,
});
في هذا المثال، يتم تمرير الخاصية counter من الحالة العامة إلى المكون كـ prop.
دالة mapDispatchToProps
هي دالة اختيارية أيضًا، تُتيح للمكون إرسال أحداث (actions) إلى المخزن. يمكن أن تكون دالة أو كائنًا من الإجراءات الجاهزة.
javascriptconst mapDispatchToProps = (dispatch) => ({
increment: () => dispatch({ type: 'INCREMENT' }),
});
أو باستخدام طريقة مختصرة:
javascriptconst mapDispatchToProps = {
increment,
};
مثال تطبيقي كامل
javascript// actions.js
export const increment = () => ({ type: 'INCREMENT' });
export const decrement = () => ({ type: 'DECREMENT' });
// reducer.js
const initialState = { counter: 0 };
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return { counter: state.counter + 1 };
case 'DECREMENT':
return { counter: state.counter - 1 };
default:
return state;
}
};
export default counterReducer;
// CounterComponent.jsx
import React from 'react';
const CounterComponent = ({ counter, increment, decrement }) => (
<div>
<h1>{counter}h1>
<button onClick={increment}>+1button>
<button onClick={decrement}>-1button>
div>
);
export default CounterComponent;
// ConnectedCounter.jsx
import { connect } from 'react-redux';
import CounterComponent from './CounterComponent';
import { increment, decrement } from './actions';
const mapStateToProps = (state) => ({
counter: state.counter,
});
const mapDispatchToProps = {
increment,
decrement,
};
export default connect(mapStateToProps, mapDispatchToProps)(CounterComponent);
آلية العمل خلف الكواليس
عند استدعاء connect(mapStateToProps, mapDispatchToProps)(Component)، تحدث الأمور التالية:
-
يقوم
connectبإنشاء مكون جديد يُسمى “Connected Component”. -
هذا المكون يكون مشتركًا في
storeمن خلالProvider. -
في كل مرة تتغير فيها الحالة، يتم استدعاء
mapStateToPropsتلقائيًا لتحديث خصائص المكون. -
الدالة
mapDispatchToPropsتتيح إرسال الإجراءات التي تُحدِث تغييرات في الحالة.
مقارنة بـ useSelector و useDispatch
مع إدخال الـ Hooks في React 16.8، أصبحت هناك طرق بديلة لـ connect من خلال useSelector و useDispatch. إلا أن connect ما تزال مستخدمة على نطاق واسع، خاصة في الأكواد القديمة أو عند التعامل مع مكونات صنفية (Class Components).
| الميزة | connect |
useSelector / useDispatch |
|---|---|---|
| نوع المكون | يُستخدم مع مكونات صنفية ووظيفية | يُستخدم فقط مع مكونات وظيفية |
| الأداء | أداء أعلى عند فصل الخصائص | أقل مرونة في منع إعادة التصيير |
| التنظيم | يحفّز الفصل بين المنطق والعرض | يُدمج المنطق داخل المكون مباشرةً |
| التوافق | متوافق مع الأنظمة القديمة والكبيرة | أحدث، ويُفضل في مشاريع جديدة |
تحسين الأداء باستخدام connect
تتيح connect تحسين أداء تطبيقات React عند استخدامها بشكل مدروس، وذلك من خلال:
-
فصل الحالة المطلوبة فقط: يمكن لمكون ما الاستماع فقط لأجزاء محددة من الحالة، مما يمنع إعادة التصيير غير الضرورية.
-
استخدام
ownProps: تسمح بتعديل المخرجات بناءً على الخصائص الخارجية. -
استخدام
areStatesEqualوareOwnPropsEqual: يمكن تخصيص مقارنة الحالة أو الخصائص لتجنب إعادة التصيير غير الضروري.
تنظيم الملفات في مشروع يستخدم connect
من الأفضل عند استخدام connect تقسيم الملفات والمجلدات بطريقة منظمة، مثل:
bash/src /components CounterComponent.jsx /containers ConnectedCounter.jsx /redux /actions counterActions.js /reducers counterReducer.js store.js
يُعزّز هذا التنظيم من إمكانية إعادة الاستخدام، وسهولة الفهم والصيانة.
تحديات وصعوبات محتملة عند استخدام connect
-
تعقيد الربط في المكونات الكبيرة: كلما زاد تعقيد
mapStateToPropsوmapDispatchToProps، زادت صعوبة تتبع التحديثات. -
صعوبة تتبع الأخطاء: عند وجود عدة مكونات مرتبطة بنفس الجزء من الحالة، قد يكون من الصعب تحديد المكون المسبب لتغيير غير متوقع.
-
الإفراط في استخدام
connect: يُفضل عدم ربط كل مكون بـ store؛ بل استخدام مبدأ “الوعاء والمحتوى” (container/presentational components).
متى يُفضّل استخدام connect؟
رغم الاتجاه الحديث نحو استخدام Hooks، إلا أن connect تبقى خيارًا موثوقًا في الحالات التالية:
-
وجود مكونات صنفية (Class Components).
-
الحاجة إلى تحسين الأداء وتقليل إعادة التصيير.
-
وجود قاعدة شيفرة كبيرة تستخدم
connectبالفعل. -
وجود منطق معقّد في
mapStateToPropsيصعب ترجمته بـuseSelector.
الخلاصة
تُعتبر الدالة connect أحد المفاتيح الأساسية للدمج بين React وRedux، إذ توفّر وسيلة فعّالة ومنظمة لربط المكونات بحالة التطبيق. ورغم ظهور تقنيات أحدث كـ Hooks، إلا أن connect لا تزال تُستخدم على نطاق واسع في التطبيقات الكبيرة والمشاريع ذات البنية التقليدية. من خلال فهم عميق لكيفية عمل connect، يمكن بناء تطبيقات قوية، مرنة وقابلة للصيانة طويلة الأمد.
المراجع:

