أهلاً بيك يا صديقي المطور في أهم نقلة عقلية وهندسية هتعملها في حياتك كمطور ووردبريس: النموذج الذهني لـ React (The React Mental Model) داخل محرر Gutenberg.
لو أنت زي ملايين المبرمجين اللي بدأوا رحلتهم مع ووردبريس الكلاسيكي، فأنت متبرمج عصبياً على أسلوب “البرمجة الإجرائية والأمرية” (Imperative Programming) باستخدام PHP و jQuery. النموذج ده كان معتمد على إنك بتمسك عنصر الـ DOM بإيدك وتأمره باللي يعمله: “روح يا جافاسكريبت دور على الزرار اللي الـ ID بتاعه #submit-btn، ولما المستخدم يدوس عليه، غير النص بتاعه لـ ‘جاري التحميل’، وروح للعنصر #alert وشيل منه كلاس hidden وحط كلاس active!”.
أول ما المطور ده بيدخل عالم Gutenberg و React، بيبدأ يتخبط ويصطدم بجدار خرساني؛ لإن React مش بتفكر كده خالص! في React، إنت مبتمسكش الـ DOM ولا بتأمره يعمل حاجة، بل بتتعامل مع معادلة رياضية عبقرية وبسيطة: UI = f(State): واجهة المستخدم هي دالة صافية في حالة البيانات! في الدليل التفصيلي ده، هنفكك النقلة الفكرية من jQuery لـ React، إزاي تفهم تدفق البيانات أحادي الاتجاه (Unidirectional Data Flow)، الفرق الجوهري بين Props و State و Attributes، وأشهر 5 أخطاء كارثية بيقع فيها مطورو PHP مع دراسة حالة مصرية حقيقية بالعامية المصرية التقنية الأصيلة.
| المعيار المعماري | النمط الأمري الكلاسيكي (jQuery / Vanilla) | النموذج التصريحي لـ React في Gutenberg | إدارة الحالة بالسيرفر في PHP الكلاسيكي |
|---|---|---|---|
| فلسفة التحكم في الواجهة (UI Philosophy) | أمرية (Imperative): “كيف تفعل” خطوة بخطوة بالبحث في شجرة الـ DOM وتعديلها. | تصريحية (Declarative): “ماذا تريد أن يظهر” بناءً على الحالة الحالية للبيانات. | توليد الـ HTML في دورة واحدة على السيرفر وإرساله كصفحة كاملة للمتصفح. |
| التعامل مع شجرة الدوم (DOM Interaction) | تعديل مباشر على الـ Real DOM عبر دوال مثل .append() أو .html(). | تعديل آمن في الـ Virtual DOM؛ و React هي المسؤولة عن تحديث الـ DOM الفعلي بأقل تكلفة. | الـ DOM يتكون مرة واحدة عند تحميل الصفحة في المتصفح ولا يتغير إلا بطلب جديد. |
| مصدر الحقيقة للبيانات (Source of Truth) | الـ DOM نفسه هو مصدر الحقيقة! نقرأ القيم من سمات data-id أو نصوص الحقول. | كائن الحالة (State & Attributes) في الذاكرة هو المصدر الوحيد، والواجهة مجرد انعكاس له. | قاعدة البيانات وجلسات المستخدم (Session / Database Variables). |
| تدفق البيانات (Data Flow) | عشوائي في كل الاتجاهات؛ أي سكربت يمكنه العبث بأي عنصر في أي توقيت. | أحادي الاتجاه صارم (Unidirectional): من الحالة إلى المكونات عبر الـ Props. | أحادي من السيرفر إلى المتصفح (Request-Response Lifecycle). |
| التعامل مع إعادة الرسم (Re-rendering) | يدوي؛ المطور مسؤول عن تذكر كل العناصر التي تحتاج لتحديث وإعادة طلائها. | تلقائي وذكي؛ عندما تتغير الحالة، React تعيد استدعاء الدالة وترسم الاختلافات فقط. | إعادة تحميل كاملة للصفحة (Full Page Refresh) عند كل إرسال نموذج. |
الأركان الثلاثة لمعمارية React داخل Gutenberg
عشان تبني كود جوتنبرج صلب ومحترف، لازم تفهم التوليفة الخاصة اللي بتجمع React مع نظام ووردبريس الداخلي:
1. المكونات (Components): لبنات البناء النقية
في React، كل شيء عبارة عن “مكون” (Component). المكون هو دالة جافاسكريبت بسيطة بتاخد مدخلات (Props) وبترجع كود JSX (اللي بيترجم لعناصر واجهة). دالة Edit في البلوك هي المكون الرئيسي، وبداخلها بنستخدم مكونات فرعية زي RichText، InspectorControls، ToolbarGroup، و Button.
2. الخصائص (Props): جواز السفر بين المكونات
الـ Props هي البيانات اللي بتتنقل من المكون الأب للمكون الابن. في جوتنبرج، ووردبريس بيغذي دالة Edit بمجموعة Props جاهزة ومقدسة:
attributes: كائن يحتوي على كافة الخصائص المعرفة فيblock.jsonوالمحفوظة في قاعدة البيانات.setAttributes: الدالة الرسمية الوحيدة المسموح لك باستخدامها لتعديل قيم الـ attributes.isSelected: قيمة منطقية (Boolean) تخبرك هل البلوك محدد حالياً بواسطة المحرر أم لا.clientId: المعرف الفريد الداخلي للبلوك في الذاكرة الحية لجوتنبرج.context: كائن يحتوي على البيانات الموروثة من البلوكات الأب (Block Context API).
3. مستويات الحالة الثلاثة (The Three Levels of State):
هنا تكمن النقطة الفاصلة التي تلخبط 90% من مطوري ووردبريس! في جوتنبرج، هناك ثلاثة أنواع مختلفة تماماً من الحالة (State)، وكل نوع له مكانه واستخدامه:
-
حالة المكون المحلية (Local Component State عبر useState):
تستخدم للبيانات المؤقتة العابرة الخاصة بواجهة المستخدم داخل المحرر فقط، والتي لا تريد حفظها في المقال! مثل: هل نافذة الـ Modal مفتوحة حالياً؟ هل القائمة منسدلة أم مغلقة؟ بمجرد ما المحرر يقفل الصفحة، البيانات دي بتختفي، وده مكانها الطبيعي.
-
خصائص البلوك الدائمة (Block Attributes عبر setAttributes):
دي البيانات الحقيقية اللي بتشكل محتوى المقال والمطلوب تخزينها في قاعدة البيانات في جدول
wp_posts(مثل: نصوص العناوين، معرفات الصور، ألوان البلوك، إعدادات التخطيط). -
مخزن البيانات العام (Global Core Store عبر @wordpress/data):
مخزن Redux مركزي يدير حالة المقال بالكامل وموقع ووردبريس (مثل: هل المقال جاري حفظه حالياً؟ ما هو المعرف التعريفي للكاتب؟ قائمة كافة البلوكات الموجودة في الصفحة).
تدفق البيانات أحادي الاتجاه (Unidirectional Data Flow): دورة الحياة الحقيقية
تعال نتتبع بالملي ثانية إيه اللي بيحصل لما المحرر يكتب حرف واحد في حقل نصي داخل البلوك بتاعك:
1. الكاتب يضغط حرف 'أ' في لوحة المفاتيح
↓
2. يتم إطلاق حدث (Event Trigger): onChange
↓
3. يتم استدعاء دالة: setAttributes( { title: newTitle } )
↓
4. محرر جوتنبرج يرسل Action لمخزن البيانات المركزي (Redux Store)
↓
5. المخزن يقوم بتحديث حالة البلوك بالخاصية الجديدة (Immutable Update)
↓
6. يقوم React باستدعاء دالة Edit( props ) من جديد وتمرير attributes محدثة!
↓
7. دالة Edit ترجع JSX جديد يعكس الحرف الجديد
↓
8. خوارزمية Reconciliation تقارن الـ Virtual DOM بالـ Real DOM وتحدث الحرف في الشاشة!
الدرس المعماري الأكبر: أنت لا تغير النص في الشاشة بيدك! أنت تبلغ ووردبريس بالقيمة الجديدة عبر setAttributes، وتترك React هي التي تتولى إعادة طلاء الشاشة بناءً على الحالة الجديدة.
أمثلة برمجية: الكود الكارثي بعقلية jQuery مقابل الكود التصريحي النقي
1. النموذج الكارثي: محاولة تطويع React بأسلوب jQuery العقيم
// ❌ كود كارثي مليء بالأخطاء المعمارية والمفاهيم الخاطئة!
import { useBlockProps } from '@wordpress/block-editor';
export default function Edit( { attributes, setAttributes } ) {
const blockProps = useBlockProps();
// خطأ قاتل 1: البحث المباشر في الدوم وتعديل العناصر بالأمر
const handleButtonClick = () => {
const titleElement = document.getElementById( 'my-custom-title' );
if ( titleElement ) {
titleElement.innerText = 'تم تغيير العنوان بنجاح!';
titleElement.style.color = 'red'; // تعديل مباشر يكسر React!
}
// خطأ قاتل 2: تعديل الحالة المباشر بالتحوير (Mutation)
attributes.items.push( 'عنصر جديد' ); // ممنوع منعاً باتاً!
setAttributes( { items: attributes.items } ); // لن يشعر React بالتغيير!
};
return (
{ attributes.title }
);
}لماذا يتدمر هذا البلوك؟
- استخدام
document.getElementByIdيكسر عزل المكونات؛ فلو كرر المحرر نفس البلوك 3 مرات في المقال، الكود سيعدل أول بلوك فقط ويتجاهل الباقي! - تعديل الـ DOM المباشر يختفي فوراً بمجرد أن تعيد React رسم المكون، لإن React سترسم ما هو مخزن في الـ State وليس ما عدلته في الـ DOM.
- تحوير المصفوفة بـ
pushيجعل مرجع المصفوفة في الذاكرة كما هو (Same Reference)، وبالتالي React تفترض أن البيانات لم تتغير ولا تعيد رسم الشاشة!
2. النموذج السليم: الكود التصريحي النقي مع الحفاظ على الـ Immutability
// ✅ الكود الهندسي القياسي المتوافق بنسبة 100% مع النموذج الذهني لـ React
import { useBlockProps, RichText } from '@wordpress/block-editor';
import { useState } from '@wordpress/element';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
export default function Edit( { attributes, setAttributes } ) {
const { title, items } = attributes;
// حالة محلية عابرة للواجهة فقط: هل القائمة مطوية أم مفتوحة؟
const [ isCollapsed, setIsCollapsed ] = useState( false );
const blockProps = useBlockProps( {
className: 'az-pure-react-block'
} );
// إضافة عنصر جديد بدون تحوير المصفوفة القديمة (Immutable Update)
const handleAddItem = () => {
const newItem = `عنصر إضافي رقم ${ items.length + 1 }`;
// إنشاء مصفوفة جديدة بالكامل باستخدام مشغل النشر (Spread Operator)
setAttributes( { items: [ ...items, newItem ] } );
};
return (
setAttributes( { title: newTitle } ) }
placeholder={ __( 'اكتب العنوان هنا تصريحياً...', 'az-mental' ) }
className="az-block-heading"
/>
{ /* الرندرة الشرطية (Conditional Rendering) تعتمد حصرياً على الحالة */ }
{ ! isCollapsed && (
{ items.map( ( item, index ) => (
-
{ item }
) ) }
) }
);
}أسرار القوة الهندسية في النموذج السليم:
[ ...items, newItem ]: لم نقم بلمس المصفوفة القديمة؛ بل أنشأنا مصفوفة جديدة كلياً في الذاكرة، مما يطلق مقارنة المراجع في React ويعيد رسم القائمة بسلاسة وفورية.! isCollapsed && (...): إظهار وإخفاء القائمة يتم برمجياً في الـ JSX بناءً على حالة الـisCollapsedدون الحاجة لإضافة وإزالة كلاسات CSS يدوياً عبر الـ DOM.
دراسة حالة واقعية: أزمة منصة العيادات الطبية وحجز المواعيد في مدينة نصر
خلفية المشروع وأبعاد الأزمة
منصة رعاية صحية وطب عن بُعد شهيرة في مصر تدير شبكة عيادات ومراكز طبية في مدينة نصر ومصر الجديدة والتجمع الخامس (يخدم أكثر من 180 طبيباً واستشارياً). المنصة قامت ببناء بلوك مخصص على Gutenberg لإدارة “مواعيد الكشف والخدمات الطبية المتاحة” في صفحات العيادات.
الأزمة التشخيصية (The Crisis)
فريق التطوير القديم كان مكوناً من مطوري PHP و jQuery كلاسيكيين لم يتلقوا تدريباً على النموذج الذهني لـ React:
- قام المطورون باستخدام
document.querySelectorداخل دالةEditلربط مكتبة تاريخ قديمة (jQuery Datepicker) بحقول البلوك. - كانوا يقومون بتعديل مصفوفة المواعيد المحجوزة مباشرة في الذاكرة عبر
attributes.slots.push(...)دون استخدامsetAttributesمع كائنات جديدة. - النتيجة كانت مرعبة: عندما يفتح الطبيب المقال لتعديل أسعار الكشف، كانت التعديلات لا تُحفظ في قاعدة البيانات لأن جوتنبرج لم يشعر بحدوث أي تغيير في الـ State!
- في حالات أخرى، كان اختيار طبيب معين يغير بيانات طبيب في بلوك مجاور في نفس الصفحة بسبب تضارب معرّفات الـ DOM (IDs) المشتركة!
- تم حجز أكثر من 320 موعد كشف مزدوج في نفس الساعة لنفس العيادة، مما تسبب في تكدس المرضى في غرف الانتظار وتوجيه اتهامات للمنصة بالنصب وسوء التنظيم.
الحل المعماري الجذري (The Architectural Solution)
قادت القيادة الهندسية الجديدة عملية إعادة كتابة شاملة وفق أصول وقواعد React الصارمة:
- إلغاء كافة استدعاءات jQuery ومكتبات التاريخ الخارجية وحذف كل أسطر
document.getElementByIdوquerySelectorمن البلوك نهائياً. - الاعتماد الكامل على مكونات ووردبريس الأصلية
@wordpress/componentsمثلDateTimePickerوSelectControlالمدارة تصريحياً. - تطبيق مبدأ Immutability الصارم في كافة معالجات الأحداث عبر استخدام الـ Spread Operator وحظر التعديل المباشر على مصفوفات وكائنات الـ Attributes.
- استخدام معرّفات فريدة مبنية على
clientIdلكل بلوك لضمان استقلالية العيادات المعروضة في الصفحة الواحدة عزلاً تاماً.
جدول قياس مؤشرات الأداء والاستقرار البرمجي (Metrics Table)
| مؤشر الأداء والاعتمادية | أثناء الأزمة (عقلية jQuery المتصادمة) | بعد التحول للنموذج الذهني لـ React | نسبة التحسن والوفر المحقق |
|---|---|---|---|
| أخطاء فشل حفظ المواعيد والأسعار | 68% من محاولات التحديث تفشل بصمت | 0.00% (حفظ لحظي وموثوق في كل مرة) | تحسن بنسبة 100% في سلامة البيانات |
| حوادث الحجز المزدوج وتضارب المرضى | 320 حالة حجز متضارب أسبوعياً | صفر حالات تضارب على الإطلاق | استعادة الثقة الكاملة في نظام العيادات |
| استهلاك الرام في متصفح الطبيب | 1,240 ميجابايت مع بطء ملحوظ (Memory Leaks) | 180 ميجابايت فقط (تنظيف فوري للمراجع) | تخفيض استهلاك الذاكرة بنسبة 85.4% |
| زمن استجابة واجهة اختيار المواعيد | 420 مللي ثانية لكل ضغطة زر | 12 مللي ثانية (تفاعل فوري متزامن) | تسريع الاستجابة بـ 35 ضعفاً |
الوصايا العشر للنموذج الذهني لـ React لمطوري Gutenberg
- UI = f(State) هي عقيدتك الأولى: لا تعدل الـ DOM بيدك أبداً؛ غير الحالة ودع React تتولى طلاء الواجهة.
- إياك ولمس Real DOM: احظر تماماً استخدام
document.getElementByIdأوquerySelectorأو دوال jQuery داخل ملفات البلوك. - احترم قدسية Immutability: لا تعدل المصفوفات بـ
pushأو الكائنات مباشرة؛ دائماً أنشئ نسخة جديدة عبر[ ...oldArray, newItem ]. - استخدم setAttributes للبيانات الدائمة فقط: إذا كانت المعلومة مؤقتة للواجهة ولا تهم المقال، خزنها في
useStateمحلياً. - احذر من الحلقات اللانهائية في useEffect: لا تستدعِ
setAttributesداخلuseEffectدون تحديد مصفوفة اعتماديات دقيقة وصارمة. - احسب البيانات المشتقة ولا تخزنها: إذا كان بإمكانك حساب “إجمالي السعر” بجمع المنتجات، فلا تخزنه كـ Attribute منفصل لتجنب عدم اتساق البيانات.
- اعتمد على مكونات @wordpress/components: وفر على نفسك آلاف الساعات واستخدم الحقول والأزرار القياسية المجهزة لسهولة الوصول.
- افصل المنطق عن العرض (Custom Hooks): ضع العمليات الحسابية المعقدة والاتصال بالـ API في دوال وخطافات مخصصة خارج جسم الـ JSX.
- استخدم key فريد وثابت في القوائم: لا تستخدم فهرس المصفوفة
indexكمفتاح للـkeyإذا كانت العناصر قابلة للحذف أو إعادة الترتيب. - فكر كمصمم معماري وليس ككاتب سكربتات: انظر للبلوك كنظام متكامل يدير حالته بدقة وليس مجرد كود HTML مكسو ببعض الجافاسكريبت.
المعمارية المتقدمة: رفع الحالة (State Lifting) ونمط useReducer في البلوكات المعقدة
يا صديقي المطور، لما البلوك بتاعك يكبر ويتحول من مجرد حقل نصي بسيط لأداة تفاعلية ضخمة—زي مثلاً “حاسبة قروض بنكية” أو “نظام تخصيص منتجات ووكومرس” يحتوي على 15 حقلاً وخيارات متشابكة—الاعتماد على useState منفصل لكل حقل بيبدأ يتحول لفوضى برمجية تسمى “State Spaghetti”.
هنا بنلجأ لنمطين معماريين من أصول React الاحترافية:
1. رفع الحالة (Lifting State Up):
إذا كان عندك مكونين فرعيين داخل البلوك (مثلاً: مكون منتقي المنتجات ومكون ملخص الفاتورة)، وكلاهما يحتاج لمعرفة المنتج المختار؛ لا تحاول جعل المكونين يتحدثان لبعضهما بشكل جانبي (Sibling-to-Sibling Communication). الحل الهندسي هو “رفع الحالة” للمكون الأب المشترك (دالة Edit الرئيسية)، وتمرير البيانات للأسفل كـ props، مع تمرير دالة تغيير (Callback) يستدعيها الابن عند حدوث تفاعل.
2. نمط useReducer لإدارة التحديثات المعقدة المتشابكة:
عندما يعتمد تعديل حقل معين على قيمة حقل آخر (مثلاً: تغيير مدة القرض يعيد حساب الفائدة الشهرية وإجمالي الأقساط)، فإن نمط useReducer هو الأداة المثالية لعزل منطق العمليات الحسابية عن واجهة الـ JSX.
كود عملي: إدارة حاسبة مالية متقدمة عبر useReducer في Gutenberg
/**
* إدارة حالة حاسبة التمويل العقاري داخل بلوك جوتنبرج
*/
import { useReducer } from '@wordpress/element';
import { useBlockProps } from '@wordpress/block-editor';
import { TextControl, RangeControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
// 1. الدالة الصافية لإدارة الحسابات (Pure Reducer Function)
function loanCalculatorReducer( state, action ) {
switch ( action.type ) {
case 'UPDATE_PROPERTY_PRICE': {
const price = action.payload;
const downPayment = price * ( state.downPaymentPercent / 100 );
const loanAmount = price - downPayment;
return {
...state,
propertyPrice: price,
downPaymentAmount: downPayment,
loanAmount: loanAmount,
};
}
case 'UPDATE_DOWN_PAYMENT_PERCENT': {
const percent = action.payload;
const downPayment = state.propertyPrice * ( percent / 100 );
return {
...state,
downPaymentPercent: percent,
downPaymentAmount: downPayment,
loanAmount: state.propertyPrice - downPayment,
};
}
default:
return state;
}
}
export default function Edit( { attributes, setAttributes } ) {
const blockProps = useBlockProps( { className: 'az-loan-calculator-box' } );
// 2. ربط الـ Reducer بحالة البلوك المبدئية
const [ state, dispatch ] = useReducer( loanCalculatorReducer, {
propertyPrice: attributes.propertyPrice || 2000000,
downPaymentPercent: attributes.downPaymentPercent || 20,
downPaymentAmount: 400000,
loanAmount: 1600000,
} );
// مزامنة التحديثات المعقدة مع خصائص البلوك المركزية
const handlePriceChange = ( newPrice ) => {
const val = parseFloat( newPrice ) || 0;
dispatch( { type: 'UPDATE_PROPERTY_PRICE', payload: val } );
setAttributes( { propertyPrice: val } );
};
return (
{ __( 'حاسبة التمويل العقاري التفاعلية (React Reducer)', 'az-mental' ) }
{
dispatch( { type: 'UPDATE_DOWN_PAYMENT_PERCENT', payload: val } );
setAttributes( { downPaymentPercent: val } );
} }
min={ 10 }
max={ 50 }
/>
مبلغ الدفعة المقدمة: { state.downPaymentAmount.toLocaleString() } ج.م
إجمالي مبلغ التمويل المطلوب: { state.loanAmount.toLocaleString() } ج.م
);
}
القيمة المعمارية لنمط useReducer:
لاحظ كيف تم عزل العمليات الحسابية بالكامل داخل دالة loanCalculatorReducer الصافية! هذه الدالة خالية من أي كود DOM أو React، ويمكنك كتابة اختبارات وحدة آلية (Unit Tests) لها في ثوانٍ معدودة للتأكد من دقة حسابات القروض البنكية قبل دمجها في واجهة محرر ووردبريس.
الأسئلة الشائعة حول النموذج الذهني لـ React في جوتنبرج (20 سؤالاً وجواباً تفصيلياً)
1. ما معنى العبارة الشهيرة “UI is a function of State” في ووردبريس؟
تعني أن مظهر وشكل البلوك في المحرر هو نتيجة رياضية بحتة للبيانات المخزنة في خصائص البلوك (Attributes) وحالته؛ فعندما تتغير البيانات، يعاد توليد الواجهة تلقائياً دون أي تلاعب يدوي بالـ DOM.
2. لماذا يعتبر استخدام jQuery داخل بلوكات Gutenberg خطأً فادحاً؟
لأن jQuery تقوم بتعديل الـ Real DOM مباشرة متجاوزة نظام الـ Virtual DOM في React، مما يسبب فقدان التحديثات وتضارب الحالة وظهور أخطاء التزامن الغامضة.
3. ما هو الفرق بين useState و setAttributes في جوتنبرج؟
الـ useState تخزن بيانات مؤقتة خاصة بالواجهة فقط وتختفي عند إغلاق المحرر، بينما setAttributes تحفظ البيانات بشكل دائم في عمود post_content داخل قاعدة البيانات.
4. ما هو مفهوم الـ Immutability ولماذا هو إلزامي في React؟
يعني عدم تعديل الكائنات والمصفوفات الأصلية في الذاكرة مباشرة؛ بل إنشاء نسخ جديدة منها عند التحديث، حتى تتمكن React من اكتشاف التغيير عبر مقارنة المراجع السريعة وإعادة رسم الواجهة.
5. لماذا يفشل الكود عند استخدام attributes.items.push(val)؟
لأن مرجع المصفوفة في الذاكرة يظل ثابتاً كما هو، فلا تشعر React بحدوث أي تعديل وتتجاهل إعادة رسم البلوك في شاشة المحرر.
6. ما هو الـ Virtual DOM وكيف يختلف عن الدوم العادي؟
هو نسخة افتراضية خفيفة الوزن من شجرة الـ DOM محفوظة في ذاكرة الجافاسكريبت، تقوم React بمقارنة التغييرات عليها أولاً وتحديث الأجزاء المتغيرة فقط في الدوم الحقيقي بأعلى سرعة.
7. كيف أتعامل مع إظهار وإخفاء العناصر في البلوك بدون كلاسات jQuery؟
باستخدام الرندرة الشرطية (Conditional Rendering) في الـ JSX، مثل: { isOpen && <MyComponent /> } بناءً على قيمة متغير منطقي في الـ State.
8. ما هو الـ Unidirectional Data Flow؟
هو سريان البيانات في اتجاه واحد محدد: من الحالة (State) إلى الـ Props الخاصة بالمكونات، ولا يتم تعديل الحالة إلا عبر إطلاق أحداث وتمرير دوال تحديث مثل setAttributes.
9. ما هي البيانات المشتقة (Derived State) ولماذا يحظر تخزينها؟
هي البيانات التي يمكن حسابها من خصائص أخرى موجودة بالفعل (مثل حساب السعر الإجمالي بضرب الكمية في السعر)؛ وتخزينها يسبب عدم اتساق إذا تم تحديث أحد الطرفين دون الآخر.
10. كيف أمنع حدوث حلقة إعادة رسم لانهائية (Infinite Loop)؟
بتجنب استدعاء setAttributes مباشرة في جسم دالة Edit الرئيسية دون وضعها داخل معالج حدث (Event Handler) أو داخل useEffect مع مصفوفة اعتماديات محددة.
11. ما هي وظيفة الخاصية key في قوائم React داخل البلوك؟
تساعد React على تحديد هوية كل عنصر في القائمة لمراقبة إضافته أو حذفه أو نقله بدقة دون إعادة رسم باقي عناصر القائمة بالكامل.
12. لماذا لا يُنصح باستخدام index كمفتاح key؟
لأنه إذا قام المستخدم بإعادة ترتيب العناصر أو حذف عنصر من المنتصف، فإن أرقام الفهارس ستتغير وتختلط مدخلات الحقول بين العناصر المتجاورة.
13. كيف أربط حقل إدخال نصي بحالة البلوك بطريقة نموذجية؟
بجعله حقلاً مداراً (Controlled Component)؛ تمرر قيمته عبر value={ attributes.myText } وتحدثه عبر onChange={ (val) => setAttributes({ myText: val }) }.
14. هل يحتاج المطور لتعلم JSX بالكامل للعمل على Gutenberg؟
نعم؛ الـ JSX هو البنية القياسية لكتابة واجهات React في جوتنبرج، ويسهل قراءة شجرة العناصر مقارنة بـ wp.element.createElement اليدوية.
15. كيف أصل لخصائص المقال الحالي من داخل مكون البلوك؟
باستخدام خطافات مخزن البيانات مثل useSelect( (select) => select('core/editor').getCurrentPost() ) دون الحاجة للبحث في الـ DOM.
16. ما الفارق بين المكون النقي (Pure Component) والمكون العادي؟
المكون النقي يعيد دائماً نفس مخرجات الـ JSX إذا استلم نفس الـ Props دون أي آثار جانبية خارجية (Side Effects).
17. كيف أتعامل مع نقرات الأزرار في React داخل البلوك؟
بتمرير دالة إلى خاصية onClick مباشرة، مثل: onClick={ () => doSomething() } دون الحاجة لإضافة Event Listeners يدوياً.
18. ماذا يحدث إذا قمت بحفظ خصائص البلوك ككائنات متحولة دون نسخ؟
ستحدث أخطاء عدم استجابة في المحرر، وقد لا يتم حفظ التعديلات عند الضغط على زر “تحديث المقال” في ووردبريس.
19. هل يؤثر حجم الـ State المحلية على أداء السيرفر؟
لا؛ الـ State المحلية تعمل في رام متصفح الزائر فقط ولا ترسل للسيرفر ولا تستهلك مساحة في قاعدة البيانات.
20. ما هي الخطوة الأولى لأي مطور ووردبريس كلاسيكي يريد احتراف Gutenberg؟
“انسَ تماماً كيف تجبر الدوم على التغيير بيدك، وتعلم كيف تعبر عن واجهتك كمرآة نقية لحالة بياناتك”.
المراجع الرسمية والتوثيق المعتمد
- React Official Documentation: Thinking in React Mental Model
- WordPress Developer Handbook: JavaScript and React Fundamentals in Gutenberg
- WordPress Element Package Reference (@wordpress/element)
- React Guide: Updating Arrays and Objects in State Immutably
- Gutenberg Core Architectural Notes: React Component Patterns


اترك تعليقاً
يجب أنت تكون مسجل الدخول لتضيف تعليقاً.