عرض واجهة تسجيل الدخول في الحالات الملائمة
لنعدل التطبيق بحيث لا تظهر واجهة تسجيل الدخول بشكل افتراضي:
ستظهر الواجهة عندما ينقر المستخدم على الزر "Login":
يمكن للمستخدم إغلاق الواجهة أيضًا بالنقر على الزر "Cancel".
سنبدأ بنقل نموذج تسجيل الدخول إلى المكوِّن الخاص به:
import React from 'react' const LoginForm = ({ handleSubmit, handleUsernameChange, handlePasswordChange, username, password }) => { return ( <div> <h2>Login</h2> <form onSubmit={handleSubmit}> <div> username <input value={username} onChange={handleUsernameChange} /> </div> <div> password <input type="password" value={password} onChange={handlePasswordChange} /> </div> <button type="submit">login</button> </form> </div> ) } export default LoginForm
عُرّفت الحالة وكل الدوال المتعلقة بالنموذج خارج المكوِّن وتُمرر إليه كخصائص.
لاحظ كيف أسندت الخصائص إلى المتغيرات بطريقة الإسناد بالتفكيك. ويعني ذلك أننا عوضًا عن كتابة الشيفرة التالية:
pre widget
const LoginForm = (props) => { return ( <div> <h2>Login</h2> <form onSubmit={props.handleSubmit}> <div> username <input value={props.username} onChange={props.handleChange} name="username" /> </div> // ... <button type="submit">login</button> </form> </div> ) }
حيث نحصل فيها على خصائص الكائنprop
باستعمال التابع prop.handleSubmit
، سنسند الخصائص مباشرة إلى متغيراتها.
إحدى الطرق السريعة في إضافة الوظيفة، هو تعديل الدالة loginForm
العائدة للمكوِّن App كالتالي:
const App = () => { const [loginVisible, setLoginVisible] = useState(false) // ... const loginForm = () => { const hideWhenVisible = { display: loginVisible ? 'none' : '' } const showWhenVisible = { display: loginVisible ? '' : 'none' } return ( <div> <div style={hideWhenVisible}> <button onClick={() => setLoginVisible(true)}>log in</button> </div> <div style={showWhenVisible}> <LoginForm username={username} password={password} handleUsernameChange={({ target }) => setUsername(target.value)} handlePasswordChange={({ target }) => setPassword(target.value)} handleSubmit={handleLogin} /> <button onClick={() => setLoginVisible(false)}>cancel</button> </div> </div> ) } // ... }
تحتوي حالة المكوِّن App الآن على المتغير المنطقي loginVisible
الذي سيقرر أتعرض واجهة تسجيل الدخول للمستخدم أم لا. تتبدل قيمة loginVisible
باستعمال زرين، ولكل منهما معالج الحدث الخاص به والمعرّف مباشرة داخل المكون:
<button onClick={() => setLoginVisible(true)}>log in</button> <button onClick={() => setLoginVisible(false)}>cancel</button>
تُحدَّد إمكانية ظهور المكوِّن بتنسيقه ضمن السياق، حيث سيختفي المكوًن إن كانت قيمة الخاصية display هي (none).
const hideWhenVisible = { display: loginVisible ? 'none' : '' } const showWhenVisible = { display: loginVisible ? '' : 'none' } <div style={hideWhenVisible}> // button </div> <div style={showWhenVisible}> // button </div>
لاحظ أننا استخدمنا مجددًا العامل"؟" ثلاثي المعاملات. إن كان المتغير loginVisible
"صحيحًا"، ستحمل قاعدة CSS للمكوِّن القيمة التالية:
display: 'none';
وإن كان loginVisible
"خاطئًا"، لن تحمل الخاصية display
أية قيمة تتعلق بعرض المكوِّن.
المكونات الأبناء (أو المصفوفة props.children)
يُعتبر منطق الشيفرة التي تتحكم بظهور نموذج تسجيل الدخول مستقل بذاته، لهذا من الأجدى أن ننقلها إلى مكوّن جديد خاص بها.
هدفنا حاليًا إضافة مكوِّن متبدّل (Togglable) يُستخدم بالطريقة التالية:
<Togglable buttonLabel='login'> <LoginForm username={username} password={password} handleUsernameChange={({ target }) => setUsername(target.value)} handlePasswordChange={({ target }) => setPassword(target.value)} handleSubmit={handleLogin} /> </Togglable>
تختلف طريقة استخدام المكوِّن قليلًا عن المكوٍّنات السابقة. فللمكوّن معرفات بداية ونهاية تحيط بمكوّن LoginForm
. تصطلح React على تسمية المكوًّن LoginForm
بالمكوِّن الإبن للمكوِّن Togglable
.
يمكننا إضافة عناصر React بين معرفي البداية والنهاية للمكوِّن Togglable
كما في المثال التالي:
<Togglable buttonLabel="reveal"> <p>this line is at start hidden</p> <p>also this is hidden</p> </Togglable>
الشيفرة التالية هي شيفرة المكوِّن Togglable
:
import React, { useState } from 'react' const Togglable = (props) => { const [visible, setVisible] = useState(false) const hideWhenVisible = { display: visible ? 'none' : '' } const showWhenVisible = { display: visible ? '' : 'none' } const toggleVisibility = () => { setVisible(!visible) } return ( <div> <div style={hideWhenVisible}> <button onClick={toggleVisibility}>{props.buttonLabel}</button> </div> <div style={showWhenVisible}> {props.children} <button onClick={toggleVisibility}>cancel</button> </div> </div> ) } export default Togglable
إن الجزء الجديد والمهم في الشيفرة هي الخاصية props.children، والتي يستخدم في الإشارة إلى المكوِّنات الأبناء لمكوِّن، والتي تمثل عناصر React الموجودة ضمن معرفي بداية ونهاية المكوّن.
ستصيّر الآن المكونات الأبناء بالشيفرة ذاتها التي تصيّر المكون الأب:
<div style={showWhenVisible}> {props.children} <button onClick={toggleVisibility}>cancel</button> </div>
وعلى خلاف الخصائص الاعتيادية التي رأيناها سابقًا يضاف "الأبناء" تلقائيًا من قبل React وتكون موجودة دائمًا.
لو عرّفنا مكوّنًا له معرف نهاية تلقائي "</" كالمكوِّن التالي:
<Note key={note.id} note={note} toggleImportance={() => toggleImportanceOf(note.id)} />
ستشكل الخاصية props.children
مصفوفة فارغة.
يمكن إعادة استعمال المكوِّن togglable
لإضافة خاصية العرض والإخفاء للنموذج الذي استخدمناه في إنشاء ملاحظة جديدة.
قبل أن نفعل ذلك، لننقل شيفرة نموذج إنشاء الملاحظات الجديدة إلى مكوِّن مستقل:
const NoteForm = ({ onSubmit, handleChange, value}) => { return ( <div> <h2>Create a new note</h2> <form onSubmit={onSubmit}> <input value={value} onChange={handleChange} /> <button type="submit">save</button> </form> </div> ) }
سنعرّف تاليًا مكوِّن النموذج داخل المكوّن Togglable
:
<Togglable buttonLabel="new note"> <NoteForm onSubmit={addNote} value={newNote} handleChange={handleNoteChange} /> </Togglable>
يمكنك إيجاد الشيفرة الكاملة لتطبيقنا الحالي ضمن الفرع part5-4 في المستودع المخصص للتطبيق على GitHub.
حالة النماذج
تتواجد حالة التطبيق في المكون الأعلى App. حيث ينص توثيق React على ما يلي بخصوص مكان تواجد الحالة:
اقتباسعادة ما تحتاج عدة مكوِّنات أن تعكس نفس التغيرات في الحالة. لهذا نوصي بنقل الحالة المشتركة لتكون داخل المكوّن الأب الأقرب إلى كل المكوِّنات الأبناء.
لو فكرنا قليلًا بحالة النماذج التي يضمها التطبيق، فلن يحتاج المكوّن App، على سبيل المثال، محتوى الملاحظة الجديدة قبل إنشائها. لذلك يمكننا بالمثل نقل حالة النماذج إلى مكوِّن خاص بها.
سيتغيّر مكِّون الملاحظة إلى الشكل التالي:
import React, {useState} from 'react' const NoteForm = ({ createNote }) => { const [newNote, setNewNote] = useState('') const handleChange = (event) => { setNewNote(event.target.value) } const addNote = (event) => { event.preventDefault() createNote({ content: newNote, important: Math.random() > 0.5, }) setNewNote('') } return ( <div> <h2>Create a new note</h2> <form onSubmit={addNote}> <input value={newNote} onChange={handleChange} /> <button type="submit">save</button> </form> </div> ) } export default NoteForm
نُقلت صفة الحالة newNote
ومعالج الحدث المسؤول عن تغييرها من المكوِّن App إلى المكوِّن المسؤول عن نموذج الملاحظات. وبقيت فقط الخاصية createNote
وهي دالة يستدعيها النموذج عندما تُنشأ ملاحظة جديدة.
سيغدو المكوّن أبسط بعد إزالة الحالة newNote
ومعالج الحدث المرتبط بها. ستستقبل الدالة addNote
التي تنشئ ملاحظة جديدة هذه الملاحظة كوسيط، وهذه الدالة هي الصفة الوحيدة التي أرسلناها إلى النموذج:
const App = () => { // ... const addNote = (noteObject) => { noteService .create(noteObject) .then(returnedNote => { setNotes(notes.concat(returnedNote)) }) } // ... const noteForm = () => ( <Togglable buttonLabel='new note'> <NoteForm createNote={addNote} /> </Togglable> ) // ... }
يمكن أن نكرر هذه العملية على نموذج تسجيل الدخول، لكننا سنترك ذلك للتمارين الإختيارية.
يمكنك إيجاد شيفرة التطبيق في الفرع part5-5 على GitHub.
إنشاء مراجع إلى المكوِّنات باستعمال ref
جميع الإضافات التي أجريت على التطبيق جيدة، لكن هناك ناحية واحدة يمكن تحسينها.
من المنطقي إخفاء نموذج إضافة الملاحظات بعد أن ننشئ الملاحظة الجديدة، لأن النموذج سيبقى ظاهرًا في الوضع الحالي. لكن هناك مشكلة صغيرة في ذلك، فمن يتحكم بعرض النماذج هو المتغير visible
الموجود داخل المكوِّن Tooglable
. فما هي الطريقة التي تمكننا من الوصول إليه، وهو خارج مكوّن النموذج؟
هناك طرق عديدة لإغلاق النموذج من المكوّن الأب، لكننا سنستعمل آلية المرجع ref الخاصة بالمكتبة React والتي تؤمن مرجعًا إلى المكوِّن.
لنعدّل المكوّن App ليصبح كالتالي:
import React, { useState, useRef } from 'react' const App = () => { // ... const noteFormRef = useRef() const noteForm = () => ( <Togglable buttonLabel='new note' ref={noteFormRef}> <NoteForm createNote={addNote} /> </Togglable> ) // ... }
يستخدم الخطاف useRef لإنشاء مرجع إلى المتغير noteFormRef
ويسند إلى المكوّن Togglable
الذي يحتوي نموذج إنشاء ملاحظة. وبالتالي سيعمل المتغير noteFormRef
كمرجع إلى المكوّن. يضمن الخطاف أن يبقى المرجع كما هو عند إعادة تصيير المكوِّن.
عدّلنا أيضًا المكون Togglable
ليصبح على الشكل التالي:
import React, { useState, useImperativeHandle } from 'react' const Togglable = React.forwardRef((props, ref) => { const [visible, setVisible] = useState(false) const hideWhenVisible = { display: visible ? 'none' : '' } const showWhenVisible = { display: visible ? '' : 'none' } const toggleVisibility = () => { setVisible(!visible) } useImperativeHandle(ref, () => { return { toggleVisibility } }) return ( <div> <div style={hideWhenVisible}> <button onClick={toggleVisibility}>{props.buttonLabel}</button> </div> <div style={showWhenVisible}> {props.children} <button onClick={toggleVisibility}>cancel</button> </div> </div> ) }) export default Togglable
تُغلَّف الدالة التي تنشئ المكوّن داخل استدعاء الدالة forwardRef، وبالتالي سيتمكن المكوّن من الوصول إلى المرجع الذي أسند إليه. يستخدم المكوِّن الخطاف useImperativeHandle ليجعل الدالة toggleVisibility
متاحة خارج إطار المكوِّن.
سنتمكن الآن من إخفاء النموذج بتنفيذ الأمر ()noteFormRef.current.toggleVisibility
بعد أن تُنشأ الملاحظة الجديدة:
const App = () => { // ... const addNote = (noteObject) => { noteFormRef.current.toggleVisibility() noteService .create(noteObject) .then(returnedNote => { setNotes(notes.concat(returnedNote)) }) } // ... }
ولكي نلخص ما مضى، فإن الدالة useImperativeHandle هي خطاف يستخدم لتعريف دوال داخل المكوِّن يمكن استدعاؤها من خارجه.
تنجح هذه الحيلة في تغيير حالة المكوِّن، لكنها مزعجة قليلًا. وقد كان بالإمكان إنجاز الوظيفة نفسها وبأسلوب أوضح مستخدمين طريقة المكوّنات المعتمدة على الأصناف التي اعتمدتها React القديمة. سنلقي نظرة على هذه الأصناف في القسم 7. إذًا فهي الحالة الوحيدة التي يكون فيها استخدام خطافات React أقل وضوحًا من مكوِّنات الأصناف.
تستخدم المراجع في عدة حالات أخرى مختلفة غير الوصول إلى مكوِّنات React.
يمكنك أن تجد شيفرة التطبيق بأكملها ضمن الفرع part5-6 في المستودع الخاص بالتطبيق على GitHub
نقطة أخرى حول المكوّنات
عندما نعرّف مكوّنًا في React كالتالي:
const Togglable = () => ... // ... }
ونستخدمه بالشكل:
<div> <Togglable buttonLabel="1" ref={togglable1}> first </Togglable> <Togglable buttonLabel="2" ref={togglable2}> second </Togglable> <Togglable buttonLabel="3" ref={togglable3}> third </Togglable> </div>
سنكون قد أنشأنا ثلاثة مكوّنات منفصلة ولكل منها حالته المستقلة:
وتستخدم الصفة ref
لإسناد مرجع لكل مكوّن ضمن المتغيرات togglable1
وtogglable2
وtogglable3
.
التمارين 5.5 - 5.10
5.5 واجهة أمامية لقائمة المدونات: الخطوة 5
غيّر نموذج إنشاء مدوّنة لكي يعرض عند الحاجة فقط. استخدم الأسلوب الذي اعتمدناه في بداية هذا الفصل. يمكنك إن أردت استعمال المكوّن Togglable
الذي أنشأناه سابقًا.
يجب أن لا يظهر النموذج بشكل افتراضي:
يظهر النموذج بالنقر على الزر "new note":
يختفي النموذج عند إنشاء مدونة جديدة.
5.6 واجهة أمامية لقائمة المدونات: الخطوة 6
افصل شيفرة نموذج إنشاء مدونة جديدة وضعها في مكوِّنها الخاص (إن لم تكن قد فعلت ذلك مسبقًا)، ثم انقل كل الحالات التي يتطلبها إنشاء مدونة جديدة إلى هذا المكوِّن.
يجب أن يعمل المكوِّن بشكل مشابه للمكوِّن NoteForm
الذي أنشأناه سابقًا في هذا الفصل.
5.7 واجهة أمامية لقائمة المدونات: الخطوة 7 *
لنضف زرًا إلى كل مدونة ليتحكم بإظهار كل تفاصيل المدونة أو عدم إظهارها. حيث تظهر كل التفاصيل بالنقر على الزر
وتختفي التفاصيل بالنقر على الزر ثانيةً.
لا حاجة أن ينفذ الزر "like" أي شيء حاليًا.
يستخدم التطبيق في الصورة السابقة بعض قواعد CSS لتحسين المظهر، ومن السهل القيام بذلك إن أدرجت قواعد التنسيق ضمن السياق، كما فعلنا في القسم 2.
const Blog = ({ blog }) => { const blogStyle = { paddingTop: 10, paddingLeft: 2, border: 'solid', borderWidth: 1, marginBottom: 5 } return ( <div style={blogStyle}> <div> {blog.title} {blog.author} </div> // ... </div> )}
ملاحظة: على الرغم من أن الوظيفة التي أضيفت هنا مطابقة تمامًا للوظيفة التي ينفذها بها المكوِّنToggleable
، لا يمكنك استخدام هذا المكوِّن مباشرة لتحقيق المطلوب في هذا التمرين. سيكون الحل الأسهل بإضافة حالة إلى المنشور تتحكم بالنموذج الذي يعرضه.
5.8 واجهة أمامية لقائمة المدونات: الخطوة 8 *
اضف وظيفةً لزر الاعجابات. يزداد عدد الإعجابات بإرسال طلب HTTP-PUT إلى عنوان المدونة الفريد في الواجهة الخلفية. وطالما أن العملية في الواجهة الخلفية ستستبدل المنشور كاملًا، عليك إرسال كل حقول المنشور ضمن جسم الطلب.
فلو أردت إضافة إعجاب إلى المنشور التالي:
{ _id: "5a43fde2cbd20b12a2c34e91", user: { _id: "5a43e6b6c37f3d065eaaa581", username: "mluukkai", name: "Matti Luukkainen" }, likes: 0, author: "Joel Spolsky", title: "The Joel Test: 12 Steps to Better Code", url: "https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-steps-to-better-code/" },
عليك إرسال طلب HTTP-PUT إلى العنوان api/blogs/5a43fde2cbd20b12a2c34e91/، يتضمن البيانات التالية:
{ user: "5a43e6b6c37f3d065eaaa581", likes: 1, author: "Joel Spolsky", title: "The Joel Test: 12 Steps to Better Code", url: "https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-steps-to-better-code/" }
تحذير من جديد: إن لاحظت أنك تستخدم await/async مع then فتأكد أنك سترتكب خطأً ما. استخدم أحد الأسلوبين وليس كلاهما في الوقت ذاته.
5.9 واجهة أمامية لقائمة المدونات: الخطوة 9 *
عدّل التطبيق ليرتب المنشورات وفقًا لعدد الإعجابات التي تحملها. يمكن ترتيب المنشورات باستخدام تابع المصفوفات sort.
5.10 واجهة أمامية لقائمة المدونات: الخطوة 10 *
أضف زرًا لحذف منشور. وأضف أيضًا وسيلة لحذف المنشورات في الواجهة الخلفية.
قد يبدو تطبيقك مشابهًا للشكل التالي:
يمكنك إظهار رسالة لتأكيد الحذف باستخدام الدالة window.confirm.
أظهر زر حذف المنشور إذا كان المستخدم الحالي للتطبيق هو من أنشأ هذا المنشور.
الحزمة PropTypes والخصائص النمطية
يفترض المكوِّن Togglable
أنه سيحصل على النص الذي سيظهر على الزر عبر الخاصية buttonLabel
، فلو نسينا تحديد ذلك في المكوِّن:
<Togglable> buttonLabel forgotten... </Togglable>
سيعمل التطبيق، لكن سيصيّر المتصفح الزر الذي لا يحمل نصًا.
لذلك قد نرغب أن نجعل وجود قيمة للنص الذي سيظهر كعنوان على الزر أمرًا إجباريًا عند استخدام المكوِّن Togglable
. يمكننا تحديد الخصائص المتوقعة والضرورية (الخصائص النمطية) باستخدام الحزمة prop-types. لنثبت الحزمة إذًا
npm install prop-types
يمكننا تحدد الخاصية buttonLabel
كخاصية إجبارية أو كخاصية نصية لازمة كالتالي:
import PropTypes from 'prop-types' const Togglable = React.forwardRef((props, ref) => { // .. }) Togglable.propTypes = { buttonLabel: PropTypes.string.isRequired }
ستعرض الطرفية رسالة الخطأ التالية إذا لم نحدد قيمة الخاصية:
سيعمل التطبيق، فلا يمكن إجبارنا على تحديد الخصائص سوى تعريفات الخصائص النمطية PropTypes. لكن تذكر أن ترك رسائل غير مقروءة على طرفية المتصفح، هو أمر غير مهني على الإطلاق.
لنعرِّف خصائص نمطية للمكوِّن LoginForm
.
import PropTypes from 'prop-types' const LoginForm = ({ handleSubmit, handleUsernameChange, handlePasswordChange, username, password }) => { // ... } LoginForm.propTypes = { handleSubmit: PropTypes.func.isRequired, handleUsernameChange: PropTypes.func.isRequired, handlePasswordChange: PropTypes.func.isRequired, username: PropTypes.string.isRequired, password: PropTypes.string.isRequired }
إن كان نمط الخاصية الممررة خاطئًا، كأن نعرف مثلًا الخاصية handleSubmit
كنص، سيتسبب ذلك برسالة التحذير التالية:
المدقق ESlint
هيئنا في القسم 3 مدقق تنسيق الشيفرة ESlint ليعمل مع الواجهة الخلفية. سنستخدمه الآن مع الواجهة الأمامية.
يثبت البرنامج Create-react-app المدقق ESlint تلقائيًا في المشروع، وكل ما يبقى علينا هو كتابة تعليمات التهيئة المطلوبة داخل الملف eslintrc.js.
ملاحظة: لا تنفذ الأمر eslint --init
. سيثبت هذا الأمر آخر نسخة من ESlint والتي لن تتوافق مع ملف التهيئة الذي ينشئه createreactapp.
سنبدأ تاليًا باختبار الواجهة الأمامية. ولكي نتجنب أخطاء التدقيق غير المرغوبة أو التي لا تتعلق بشيفرتنا، سنثبت الحزمة eslint-jest-plugin:
npm add --save-dev eslint-plugin-jest
لننشئ الملف eslintrc.js الذي يحتوي الشيفرة التالية:
module.exports = { "env": { "browser": true, "es6": true, "jest/globals": true }, "extends": [ "eslint:recommended", "plugin:react/recommended" ], "parserOptions": { "ecmaFeatures": { "jsx": true }, "ecmaVersion": 2018, "sourceType": "module" }, "plugins": [ "react", "jest" ], "rules": { "indent": [ "error", 2 ], "linebreak-style": [ "error", "unix" ], "quotes": [ "error", "single" ], "semi": [ "error", "never" ], "eqeqeq": "error", "no-trailing-spaces": "error", "object-curly-spacing": [ "error", "always" ], "arrow-spacing": [ "error", { "before": true, "after": true } ], "no-console": 0, "react/prop-types": 0 }, "settings": { "react": { "version": "detect" } } }
ملاحظة: إن كنت تستخدم ESlint كإضافة مع Visual Studio Code، قد تحتاج إلى إعدادات إضافية لفضاء العمل حتى يعمل. وإن كنت ترى الرسالة:
اقتباس"Failed to load plugin react: Cannot find module 'eslint-plugin-react"
فهذا دليل على أنك تحتاج إلى مزيد من تعليمات التهيئة.
قد يؤدي إضافة الأمر "eslint.workingDirectories": [{ "mode": "auto" }]
إلى الملف setting.json في فضاء العمل إلى حل المشكلة. يمكنك الاطلاع على المزيد حول الموضوع عبر الانترنت.
لننشئ ملف تجاهل قواعد eslint ذو اللاحقة eslintignore. بحيث يحتوي الشيفرة التالية:
node_modules build
وهكذا لن تخضع المجلدات "build" و"node_modules" لعملية التدقيق.
لننشئ أيضًا سكربت npm لتشغيل المدقق:
{ // ... { "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "server": "json-server -p3001 db.json", "eslint": "eslint ." }, // ... }
سيسبب المكوِّن تحذيرًا مزعجًا: "لا يحمل تعريف المكوِّن اسمًا لعرضه" (Component definition is missing display name).
وستكشف أداة تطوير React أيضًا أن المكوِّن لا يحمل اسمًا:
لكن إصلاح ذلك أمر يسير.
import React, { useState, useImperativeHandle } from 'react' import PropTypes from 'prop-types' const Togglable = React.forwardRef((props, ref) => { // ... }) Togglable.displayName = 'Togglable' export default Togglable
يمكنك إيجاد شيفرة التطبيق بالكامل ضمن الفرع part5-7 في الستودع الخاص بالتطبيق على GitHub.
التمرينان 5.11 - 5.12
5.11 واجهة أمامية لقائمة المدونات: الخطوة 11
عرّف خاصة نمطية propTypes لأحد مكوِّنات التطبيق.
5.12 واجهة أمامية لقائمة المدونات: الخطوة 12
أضف المدقق ESlint إلى التطبيق. أضف ما ترغب من قواعد التهيئة إلى المدقق، وأصلح كل الأخطاء الناتجة عنه.
يثبت البرنامج create-react-app المدقق ESlint تلقائيًا في المشروع، وكل ما يبقى عليك هو كتابة تعليمات التهيئة المطلوبة داخل الملف eslintrc.js.
ملاحظة: لا تنفذ الأمر eslint --init
. سيثبت هذا الأمر آخر نسخة من ESlint والتي لن تتوافق مع ملف التهيئة الذي ينشئه create-react-app.
ترجمة -وبتصرف- للفصل props.children, proptypes من سلسلة Deep Dive Into Modern Web Development
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.