diff --git a/src/content/learn/reacting-to-input-with-state.md b/src/content/learn/reacting-to-input-with-state.md index 970b4e79b..a18fbc5a3 100644 --- a/src/content/learn/reacting-to-input-with-state.md +++ b/src/content/learn/reacting-to-input-with-state.md @@ -4,36 +4,35 @@ title: الاستجابة للمدخلات باستخدام الحالة -React توفر طريقة تصريحيّة (declarative) لتعديل واجهة المستخدم (UI). بدلا من تعديل أجزاء منفردة من واجهة المستخدم مباشرة، يمكنك وصف الحالات المختلفة التي يأخذها مكوّنك، والانتقال بينهم كاستجابة لمدخلات المستخدم. هذا مشابه لتصور المصممين عن واجهة المستخدم. +React توفر طريقة تصريحيّة (declarative) لتعديل واجهة المستخدم (UI). بدلًا من تعديل أجزاء منفردة من واجهة المستخدم مباشرةً، يمكنك وصف الحالات المختلفة التي يأخذها مكوّنك، والانتقال بينهم كاستجابة لمدخلات المستخدم. هذا مشابه لتصوّر المصمّمين عن واجهة المستخدم. -* كيف تختلف البرمجة التصريحية لواجهة المستخدم (declarative UI programming) عن البرمجة الأمرية لواجهة المستخدم (imperative UI programming) +* كيف تختلف البرمجة التصريحيّة لواجهة المستخدم (declarative UI programming) عن البرمجة الأمريّة لواجهة المستخدم (imperative UI programming) * كيفية استعراض الحالات المرئية المختلفة التي يأخذها مكوّنك * كيفية تنشيط التغييرات بين الحالات المرئية المختلفة من خلال الكود -## كيف تُقارَن واجهة المستخدم التصريحية (declarative UI) بالأمرية (imperative) {/*how-declarative-ui-compares-to-imperative*/} +## كيف تُقارَن واجهة المستخدم التصريحيّة (declarative UI) بالأمريّة (imperative) {/*how-declarative-ui-compares-to-imperative*/} -عندما تصمم تعاملات واجهة المستخدم، عليك غالبًا التفكير في كيفية *تغيّر* واجهة المستخدم كاستجابة لاجراءات المستخدم. فكر في نموذج يسمح للمستخدم بإرسال إجابة: +عندما تصمم تعاملات واجهة المستخدم، عليك غالبًا التفكير في كيفية *تغيّر* واجهة المستخدم كاستجابة لإجراءات المستخدم. فكر في نموذج يسمح للمستخدم بإرسال إجابة: -* عندما تكتب شيئًا داخل النموذج، الزر "أرسل" **يصبح مفعلًا.** -* عندما تضغط على "أرسل"، كلٌ من النموذج والزر **يصبح معطلا** ومؤشر التحميل **يظهر.** -* لو نجح طلب الشبكة، النموج **يبدأ بالاختفاء،** ورسالة "شكرًا لك" **تظهر.** -* لو فشل طلب الشبكة، رسالة خطأٍ **تظهر،** والنموذج **يصبح مفعلًا** مجددا. +* عندما تكتب شيئًا داخل النموذج، يصبح الزر "أرسل" **مفعلًا.** +* عندما تضغط على "أرسل"، يصبح كلٌ من النموذج والزر **معطلا** و**يظهر** مؤشر التحميل. +* لو نجح طلب الشبكة، يبدأ النموج **بالاختفاء،** و**تظهر** رسالة "شكرًا لك". +* لو فشل طلب الشبكة،**تظهر** رسالة خطأٍ، ويصبح النموذج **مفعلًا** مجددا. -في **البرمجة الأمرية (imperative programming)**، يتوافق ما ذُكر أعلاه مباشرة مع طريقة تطبيق التعاملات. عليك أن تكتب التعليمات التامة لتعديل واجهة المستخدم معتمدا على ما حصل للتو. إليك طريقة أخرى لتفكر في هذا الأمر: تخيل نفسك راكبا إلى جانب أحدهم في سيارة مع إخباره في كل منعطف تلو الآخر عن وجهة الذهاب. +في **البرمجة الأمرية (imperative programming)**، يتوافق ما ذُكر أعلاه مباشرة مع طريقة تطبيق التعاملات. عليك أن تكتب التعليمات التامّة لتعديل واجهة المستخدم معتمدًا على ما حصل للتوّ. إليك طريقة أخرى لتفكر في هذا الأمر: تخيل نفسك راكبًا إلى جانب أحدهم في سيارة مع إخباره في كل منعطف تلو الآخر عن وجهة الذهاب. -هم لا يعلمون إلى أين تريد أن تذهب، هم يتبعون أوامرك فقط. (ولو أنك أعطيتهم الاتجاهات الخاطئة، سوف ينتهي بك المطاف لوجهة خاطئة!) هذا يطلق عليه *أمري (imperative)* لأن عليك أن "تأمر" كل عنصر، بداية من مؤشر التحميل إلى الزر، مخبرًا -الكمبيوتر عن *كيفية* تحديث واجهة المستخدم (UI). +هو لا يعلم إلى أين تريد أن تذهب، هو يتبع أوامرك فقط. (ولو أنك أعطيته الاتجاهات الخاطئة، سوف ينتهي بك المطاف لوجهة خاطئة!) هذا يطلق عليه *أمري (imperative)* لأن عليك أن "تأمر" كل عنصر، بداية من مؤشر التحميل إلى الزر، مخبرًا الكمبيوتر عن *كيفية* تحديث واجهة المستخدم (UI). -في هذا المثال للبرمجة الأمرية لواجهة المستخدم، النموذج مبنيّ *بدون* React. إنه يستخدم [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model) المتصفح فقط: +في هذا المثال للبرمجة الأمريّة لواجهة المستخدم، النموذج مبنيّ *بدون* React. باستخدام [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model) الخاص بالمتصفح فقط: @@ -86,7 +85,7 @@ function submitForm(answer) { // Pretend it's hitting the network. return new Promise((resolve, reject) => { setTimeout(() => { - if (answer.toLowerCase() == 'إسطنبول') { + if (answer.toLowerCase() == 'istanbul') { resolve(); } else { reject(new Error('توقع جيد ولكن إجابة خاطئة. حاول مرة أخرى!')); @@ -127,17 +126,17 @@ textarea.oninput = handleTextareaChange; ``` -تعديل واجهة المستخدم (UI) أمريًّا يعمل بشكل جيد كفاية للأمثلة المعزولة، ولكنه يصبح أكثر صعوبة بشكل استثنائي عندما تدير أنظمة أكثر تعقيدًا. تخيل تحديث صفحة مليئة بالنماذج المختلفة مثل هذه هنا. إضافة عنصر واجهة مستخدم جديد سيتطلب فحص كامل الكود الموجود بحرص للتأكد من أنك لم تقم بعمل خطأ(على سبيل المثال، نسيان إظهار أو إخفاء شيء ما). +تعديل واجهة المستخدم (UI) أمريًّا يعمل بشكل جيد كفاية للأمثلة المعزولة، ولكنه يصبح أكثر صعوبة بشكل استثنائي عندما تدير أنظمة أكثر تعقيدًا. تخيل تحديث صفحة مليئة بالنماذج المختلفة مثل هذه هنا. إضافة عنصر واجهة مستخدم جديد سيتطلب فحص كامل الكود الموجود بحرص للتأكد من أنك لم تقم بعمل خطأ (على سبيل المثال، نسيان إظهار أو إخفاء شيء ما). React صُنعت لحل هذه المشكلة. -في React، لن تقوم بتعديل واجهة المستخدم مباشرة -- يعني أنك لن تقوم بتفعيل، تعطيل، إظهار، أو إخفاء مكوّنات مباشرة. بدلا عن ذلك، سوف **تصف ما تريده أن يظهر،** و React سوف تدبر كيفية تحديث واجهة المستخدم. فكر في أخذ سيارة أجرة وإخبار السائق إلي أين تريد أنت تذهب بدلا من إخباره إلي أين ينعطف. وظيفة السائق هي أن يوصلك إلى هناك، وربما قد يعرف اختصارات لم تأخذها أنت بالحسبان. +في React، لن تقوم بتعديل واجهة المستخدم مباشرة -- يعني أنك لن تقوم بتفعيل، تعطيل، إظهار، أو إخفاء مكوّنات مباشرة. بدلًا عن ذلك، سوف **تصف ما تريده أن يظهر،** و React سوف تدبر كيفية تحديث واجهة المستخدم. فكر في أخذ سيارة أجرة وإخبار السائق إلي أين تريد أنت تذهب بدلًا من إخباره إلي أين ينعطف. وظيفة السائق هي أن يوصلك إلى هناك، وربما قد يعرف اختصارات لم تأخذها أنت بالحُسبان. @@ -146,18 +145,18 @@ React صُنعت لحل هذه المشكلة. لقد رأيت كيفية تنفيذ نموذج أمريَّا أعلاه. لفهم أفضل لكيفية التفكير في React، سوف تمر بإعادة تنفيذ واجهة المستخدم (UI) هذه باستخدام React أدناه: 1. **عيّن** الحالات المرئية المختلفة لمكوّنك -2. **حدد** ما ينشط تغيرات تلك الحالات +2. **حدد** ما ينشط تغييرات تلك الحالات 3. **مثّل** الحالة في الذاكرة باستخدام `useState` 4. **احذف** أيّ متغيرات حالة غير ضرورية 5. **اربط** معالجات الأحداث لتعيين الحالة -### الخطوة 1: عين الحالات المرئية المختلفة لمكوّنك {/*step-1-identify-your-components-different-visual-states*/} +### الخطوة 1: عيّن الحالات المرئية المختلفة لمكوّنك {/*step-1-identify-your-components-different-visual-states*/} -في علوم الحاسب، ربما تسمع عن ["آلة حالة (state machine)"](https://en.wikipedia.org/wiki/Finite-state_machine) كونها واحدة من ضمن "حالات" متعددة.إذا كنت تعمل مع مصمم، لربما رأيت نماذج تجريبية لـ"الحالات المرئية" المختلفة +في علوم الحاسب، ربما تسمع عن ["آلة الحالة (state machine)"](https://en.wikipedia.org/wiki/Finite-state_machine) كونها واحدة من ضمن "حالات" متعددة. إذا كنت تعمل مع مصمم، لربما رأيت نماذج تجريبية لـ"الحالات المرئية" المختلفة -أولًا، أنت تحتاج لتصور جميع "الحالات" المختلفة لواجهة المستخدم (UI) التي قد يراها المستخدم: -* **فارغة**: النموذج يحتوي زر "إرسال" معطل. -* **كتابة**: النموذج يحتوي زر "إرسال" مفعّل. +أولًا، أنت تحتاج لتصوّر جميع "الحالات" المختلفة لواجهة المستخدم (UI) التي قد يراها المستخدم: +* **فارغة**: النموذج يحتوي على زر "إرسال" معطل. +* **كتابة**: النموذج يحتوي على زر "إرسال" مفعّل. * **إرسال**: النموذج معطل تمامًا. يتم عرض مؤشر التحميل. * **نجاح**: يتم عرض رسالة "شكرًا لك" بدلًا من النموذج. * **خطأ**: مثل حالة الكتابة، ولكن مع رسالة خطأ إضافية @@ -193,7 +192,7 @@ export default function Form({ -يمكنك تسمية الخاصيّة أيّ شيء تريد، التسمية ليست مهمة. جرب تعديل `status = 'empty'` إلى `status = 'success'` لترى رسالة النجاح تظهر. التجربة تتيح لك التكرار السريع على واجهة المستخدم قبل ربط أي منطق. ها هو نموذج تجريبي أكثر تفصيلًا لنفس المكوّن، يظل "متحكم" بواسطة الخاصية `status`: +يمكنك تسمية الخاصيّة أيّ شيء تريد، التسمية ليست مهمة. جرب تعديل `status = 'empty'` إلى `status = 'success'` لترى رسالة النجاح تظهر. التجربة تتيح لك التكرار السريع على واجهة المستخدم قبل ربط أي منطق. ها هو نموذج تجريبي أكثر تفصيلًا لنفس المكوّن، يظل "متحكمًا به" بواسطة الخاصية `status`: @@ -234,6 +233,7 @@ export default function Form({ ``` ```css +body { direction: rtl; } .Error { color: red; } ``` @@ -243,7 +243,7 @@ export default function Form({ #### عرض عديد من الحالات المرئية مرة واحدة {/*displaying-many-visual-states-at-once*/} -لو أن لمكون العديد من الحالات المرئية، قد يكون ملائما عرضها جميعها في صفحة واحدة: +لو أن لمكون العديد من الحالات المرئية، قد يكون ملائمًا عرضها جميعها في صفحة واحدة: @@ -302,7 +302,7 @@ export default function Form({ status }) { ```css section { border-bottom: 1px solid #aaa; padding: 20px; } h4 { color: #222; } -body { margin: 0; } +body { margin: 0; direction: rtl; } .Error { color: red; } ``` @@ -312,22 +312,22 @@ body { margin: 0; } -### الخطوة 2: حدد ما ينشط تغيرات تلك الحالة {/*step-2-determine-what-triggers-those-state-changes*/} +### الخطوة 2: حدد ما ينشط تغييرات تلك الحالة {/*step-2-determine-what-triggers-those-state-changes*/} يمكنك تنشيط تحديثات الحالة كاستجابة إلى نوعين من المدخلات: * **مدخلات الإنسان،** مثل الضغط على زر، الكتابة في حقل، زيارة رابط. -* **مدخلات الكمبيوتر** مثل وصول رد الشبكة، استكمال المؤقت، تحميل الصورة +* **مدخلات الكمبيوتر،** مثل وصول رد الشبكة، استكمال المؤقت، تحميل الصورة. - - + + -في كلتا الحالتين، **يجب عليك تعيين [متغيرات الحالة (state variables)](/learn/state-a-components-memory#anatomy-of-usestate) لتُحدّث واجهة المستخدم (UI).** من أجل النموذج الذي تطوره، سوف تحتاج لتغيير الحالة كنتيجة لقليل من المدخلات المختلفة: +في كلتا الحالتين، **يجب عليك تعيين [متغيرات الحالة (state variables)](/learn/state-a-components-memory#anatomy-of-usestate) لتُحدّث واجهة المستخدم (UI).** من أجل تطوير النموذج سوف تحتاج لتغيير الحالة كنتيجة لبعض من المدخلات المختلفة: -* **تغيرت مدخل النص** (الإنسان) سوف يغيرها من الحالة *الفارغة* إلى حالة *الكتابة* أو العكس، يعتمد على ما إذا كان حقل النص فارغًا أم لا. -* **الضغط على زر الإرسال** (الإنسان) سوف يغيرها إلى حالة *الإرسال* +* **تغيّر حقل إدخال النص** (الإنسان) سوف يغيرها من الحالة *الفارغة* إلى حالة *الكتابة* أو العكس، يعتمد على ما إذا كان حقل النص فارغًا أم لا. +* **الضغط على زر الإرسال** (الإنسان) سوف يغيرها إلى حالة *الإرسال*. * **استجابة ناجحة للشبكة** (الكمبيوتر) سوف يغيرها إلى حالة *النجاح*. * **استجابة فاشلة للشبكة** (الكمبيوتر) سوف يغيرها إلى حالة *الخطأ* مع رسالة الخطأ المناسبة. @@ -372,17 +372,17 @@ const [isSuccess, setIsSuccess] = useState(false); const [isError, setIsError] = useState(false); ``` -خطوتك المبدأئية على الأرجح لن تكون هي الأفضل، ولكن هذا لا بأس به -- إعادة تصميم الحالة هو جزء من العملية! +خطوتك المبدئية على الأرجح لن تكون هي الأفضل، ولكن هذا لا بأس به -- إعادة تصميم الحالة هو جزء من العملية! -### خطوة 4: احذف أيّ متغيرات حالة غير ضرورية {/*step-4-remove-any-non-essential-state-variables*/} +### الخطوة 4: احذف أيّ متغيرات حالة غير ضرورية {/*step-4-remove-any-non-essential-state-variables*/} -ما تريده هو تجنب تكرار محتوى الحالة لذلك أنت فقط تقوم بتعقب ما هو ضروري. قضاء قليل من الوقت في إعادة تصميم هيكل حالتك سوف يجعل مكوّنك أسهل للفهم، يقلل التكرار، ويتجنب المعاني غير المقصودة. هدفك هو **منع الأوضاع التي تكون بها الحالة في الذاكرة لا تمثل أي واجهة مستخدم صالحة تود للمستخدم أن يراها.** (على سبيل المثال، لن تريد أبدًا إظهار رسالة خطأ مع تعطيل الإدخال في نفس الوقت، أو أن المستخدم لن يكون قادرًا على تصحيح الخطأ!) +ما تريده هو تجنب تكرار محتوى الحالة لذلك أنت تقوم بتعقب ما هو ضروري فقط. قضاء قليل من الوقت في إعادة تصميم هيكل حالتك سوف يجعل مكوّنك أسهل للفهم، يقلل التكرار، ويتجنب المعاني غير المقصودة. هدفك هو **منع الأوضاع التي تكون بها الحالة في الذاكرة لا تمثل أي واجهة مستخدم صالحة من التي تود للمستخدم أن يراها.** (على سبيل المثال، لن تريد أبدًا إظهار رسالة خطأ مع تعطيل الإدخال في نفس الوقت، أو أن المستخدم لن يكون قادرًا على تصحيح الخطأ!) هنا بعض الاسئلة التي يمكن أن تسألها عن متغيرات الحالة: -* **هل هذه الحالة تسبب معضلة؟** على سبيل المثال، `isTyping` و `isSubmitting` لا يمكن لكليهما أن يكونا بقيمة `true`. المعضلة غالبا تعني أن الحالة ليست مقيدة بالشكل الكافي. هناك أربع احتمالات ممكنة لقيميتين منطقيتين (boolean). لكن ثلاث منها فقط يوافقن حالات صالحة. لحذف الحالة "المستحيلة"، يمكنك جمع تلك الحالات داخل `status` التي يجب يجب أن تكون واحدة من ثلاث قيم: `'typing'`, `'submitting'`, أو `'success'`. +* **هل هذه الحالة تسبب معضلة؟** على سبيل المثال، `isTyping` و `isSubmitting` لا يمكن لكليهما أن يكونا بقيمة `true`. المعضلة غالبًا تعني أن الحالة ليست مقيدة بالشكل الكافي. هناك أربع احتمالات ممكنة لقيميتين منطقيتين (boolean). لكن ثلاث منهن فقط يوافقن حالات صالحة. لحذف الحالة "المستحيلة"، يمكنك جمع تلك الحالات داخل `status` التي يجب أن تكون واحدة من ثلاث قيم: `'typing'`, `'submitting'`, أو `'success'`. * **هل نفس المعلومات متاحة بالفعل لمتغير حالة آخر؟** معضلة أخرى: `isEmpty` و `isTyping` لا يمكنها أن يكونا `true` في نفس الوقت. بجعلهما متغيرين حالة منفصلين، تخاطر بفقدان الترابط بينهما وإحداث الأخطاء. لحسن الحظ، يمكن حذف `isEmpty` والتحقق من `answer.length === 0` بدلًا عن ذلك. -* **هل يمكنك الحصول على نفس المعلومات من من عكس متغير حالة آخر؟** `isError` غير ضروري لأنه يمكنك التحقق من `error !== null` بدلًا عن ذلك. +* **هل يمكنك الحصول على نفس المعلومات من عكس متغير حالة آخر؟** `isError` غير ضروري لأنه يمكنك التحقق من `error !== null` بدلًا عن ذلك. بعد هذا التبسيط، تبقى لديك 3 (من أصل 7!) متغيرات حالة *ضرورية*: @@ -392,13 +392,13 @@ const [error, setError] = useState(null); const [status, setStatus] = useState('typing'); // 'typing', 'submitting', or 'success' ``` -أنت تعلم أنها ضرورية، لأنك لا تستطيع إزالة أيّ منها بدون تخريب آلية العمل +أنت تعلم أنها ضرورية، لأنك لا تستطيع إزالة أيّ منها بدون تخريب آلية العمل. #### إزالة الحالات "المستحيلة" باستخدام مخفض (reducer) {/*eliminating-impossible-states-with-a-reducer*/} -هذه الثلاث متغيرات تمثيل جيد كفاية لحالة النموذج. مع ذلك، لا تزال هناك بعض الحالات المتوسطة التي لا تشكّل معنى بصورة تامة. على سبيل المثال، `error` التي لا تحمل القيمة null ليس لها معنى عندما تكون `status` تحمل قيمة `success`. لتمثيل الحالة بطريقة أكثر دقة، يمكنك [استخلاصها إلى مخفض.](/learn/extracting-state-logic-into-a-reducer) المخفضات تتيح ليك توحيد العديد من متغيرات الحالة داخل كائن (object) واحد وتجميع كل المنطق المتعلق بها. +هذه الثلاث متغيرات تمثيل جيد كفاية لحالة النموذج. مع ذلك، لا تزال هناك بعض الحالات المتوسطة الغير منطقية بشكل كافٍ. على سبيل المثال، `error` التي لا تحمل القيمة null غير منطقية عندما تكون `status` تحمل قيمة `success`. لتمثيل الحالة بطريقة أكثر دقة، يمكنك [استخلاصها إلى مخفض.](/learn/extracting-state-logic-into-a-reducer) المخفضات تتيح ليك توحيد العديد من متغيرات الحالة داخل كائن (object) واحد وتجميع كل المنطق المتعلق بها. @@ -471,7 +471,7 @@ function submitForm(answer) { setTimeout(() => { let shouldError = answer.toLowerCase() !== 'lima' if (shouldError) { - reject(new Error('Good guess but a wrong answer. Try again!')); + reject(new Error('توقع جيد ولكن إجابة خاطئة. حاول مرة أخرى!')); } else { resolve(); } @@ -481,6 +481,7 @@ function submitForm(answer) { ``` ```css +body { direction: rtl; } .Error { color: red; } ``` @@ -493,7 +494,7 @@ function submitForm(answer) { * البرمجة التصريحية تعني وصف واجهة المستخدم لكل حالة مرئية عوضًا عن الإدارة التفصيلية لواجهة المستخدم (الأمريّة). * عند تطوير مكوّن: 1. حدد كل حالاته المرئية. - 2. عيّن منشطات الإنسان والكمبيوتر لتغيّرات الحالة. + 2. عيّن المنشطات الوادة الإنسان والكمبيوتر لتغيّرات الحالة. 3. مثل الحالة عن طريق `useState`. 4. احذف الحالة غير الضرورية لتجنب الأخطاء والمعضلات. 5. اربط معالجات الأحداث لتعيين الحالة. @@ -561,7 +562,7 @@ body { margin: 0; padding: 0; height: 250px; } * عندما تكون الصورة نشطة، أصناف CSS هي `background` و `picture picture--active`. * عندما تكون الصورة غير نشطة، أصناف CSS هي `background background--active` و `picture`. -متغير حالة قيمة منطقية (boolean) واحد كافي لتذكر ما إذا كانت نشطة. المهمة الأصلية كانت إزالة أو إضافة أصناف CSS. على أية حال، في React تحتاج لـ*تصف* ما تريد رؤيته فضلًا عن *تعديل* عناصر واجهة المستخدم. لذلك تحتاج لحساب كلا صنفيّ CSS اعتمادًا على الحالة الحالية. تحتاج أيضًا إلى [إيقاف الانتشار (propagation)](/learn/responding-to-events#stopping-propagation) بحيث لا يتم تسجيل النقر على الصورة كنقر على الخلفية. +متغير حالة قيمة منطقية (boolean) واحد يكفي لتذكر ما إذا كانت نشطة. المهمة الأصلية كانت إزالة أو إضافة أصناف CSS. على أية حال، في React تحتاج لـ*تصف* ما تريد رؤيته فضلًا عن *تعديل* عناصر واجهة المستخدم. لذلك تحتاج لحساب كلا صنفيّ CSS اعتمادًا على الحالة الحالية. تحتاج أيضًا إلى [إيقاف الانتشار (propagation)](/learn/responding-to-events#stopping-propagation) بحيث لا يتم تسجيل النقر على الصورة كنقر على الخلفية. تأكد من أن هذا الإصدار يعمل عن طريق النقر على الصور وخارجها: @@ -697,7 +698,7 @@ body { margin: 0; padding: 0; height: 250px; } -ضع في الحسبان أنه إذا وصف جزئين مختلفين من JSX الشجرة نفسها، فتضمينهما (أول `
` → أول ``) يجب أن يصطف. وإلا تغيّر `isActive` سوف يعيد إنشاء الشجرة بأكملها أدناه و [يعيد تعيين حالتها.](/learn/preserving-and-resetting-state) هذا هو السبب، إذا كان يتم إرجاع شجرة JSX مشابهة في كلا الحالتين، فمن الأفضل كتابتهما على كجزء واحد من JSX. +ضع في الحسبان أنه إذا وصف جزئين مختلفين من JSX الشجرة نفسها، فتضمينهما (أول `
` ← أول ``) يجب أن يصطف. وإلا تغيّر `isActive` سوف يعيد إنشاء الشجرة بأكملها أدناه و [يعيد تعيين حالتها.](/learn/preserving-and-resetting-state) هذا هو السبب، إذا كان يتم إرجاع شجرة JSX مشابهة في كلا الحالتين، فمن الأفضل كتابتهما كجزء واحد من JSX. @@ -793,18 +794,18 @@ lastNameInput.oninput = handleLastNameChange; ``` -هذا النموذج يتغيّر بين وضعين: في وضع التعديل، ترى حقول الإدخال، وفي وضع المعاينة، ترى النتيجة فقط. عنوان الزر يتغيّر ما بين "عدّل" و"احفظ" اعتمادًا على الوضع الذي أنت عليه. عندما تقوم بتغيير حقول الإدخال، رسالة الترحيب في الأسفل يتم تحديثها للوقت الحالي. +هذا النموذج يتغيّر بين وضعين: في وضع التعديل، ترى حقول الإدخال، وفي وضع المعاينة، ترى النتيجة فقط. عنوان الزر يتغيّر ما بين "عدّل" و"احفظ" اعتمادًا على الوضع الذي أنت عليه. عندما تقوم بتغيير حقول الإدخال، يتم تحديث رسالة الترحيب في الأسفل للوقت الحالي. مهمتك هي إعادة تنفيذها بواسطة React في الـsandbox أدناه. لضمان راحتك، تم تحويل التوصيف (markup) إلى JSX, لكن يتعين عليك جعلها تُظهر وتُخفي المدخلات كما تفعل الأصلية. -تأكد من أنها تقوم بتحد النص في الأسفل أيضًا! +تأكد من أنها تقوم بتحديث النص في الأسفل أيضًا! @@ -832,6 +833,7 @@ export default function EditProfile() { ``` ```css +body { direction: rtl; } label { display: block; margin-bottom: 20px; } ``` @@ -859,7 +861,7 @@ export default function EditProfile() { setIsEditing(!isEditing); }}>