می خواهم در این جلسه یک کامپوننت to-do list بسازم (کامپوننتی که کار های روزمره کاربر به صورت لیست به او نشان دهد) به همین دلیل در پوشه src یک پوشه دیگر به نام components بسازید که حاوی فایلی به نام TodoList.tsx باشد. اگر react بلد باشید می دانید که برای ساخت یک کامپوننت react باید آن را وارد این فایل کنیم، بنابراین:
import React from 'react'; const TodoList= () => {}; export default TodoList;
حالا به جای اینکه مثل همیشه در react عمل کنیم، از قابلیت های تایپ اسکریپت استفاده کرده و بگوییم که TodoList یک تابع عادی نیست بلکه یک تابع کامپوننتی (functional component) است:
const TodoList: React.FC = () => {};
با نوشتن این کد خطا خواهیم گرفت. چرا؟ به دلیل اینکه TodoList چیزی را برنمی گرداند تا کامپوننت حساب شود و فعلا یک تابع عادی است. برای حل این مشکل می گوییم:
import React from 'react'; const TodoList: React.FC = props => { const todos = [{ id: 't1', text: 'finish the course' }]; return <ul> {todos.map(todo => <li key={todo.id}>{todo.text}</li>)} </ul> }; export default TodoList;
همانطور که می بینید من ابتدا آرایه ای به نام todos را تعریف کرده ام که دارای یک شیء است. این شیء یک id و یک متن (Text) دارد. حالا در قسمت JSX از کامپوننت خودمان با استفاده از تابع map بین todo ها گردش می کنم و هر کدام را به صورت <li> نمایش می دهم. هر <li> دارای یک key است که در react برای عناصر رندر شده در کنار هم اجباری است و از آنجایی که قصد تدریس react را ندارم آن را توضیح نمی دهم. متن هر <li> نیز همان text موجود در todo است. گرچه فعلا فقط یک todo داریم اما کد بالا قابلیت نمایش تعداد بیشتری را نیز دارد. حالا می توانیم از کامپوننت todoList درون App استفاده کنیم بنابراین App.tsx را باز کرده و مانند من عمل کنید:
import React from 'react'; import TodoList from './components/TodoList';
ابتدا آن را وارد App.tsx کرده ام. همچنین نیازی به نوشتن پسوند tsx نیست چرا که ما از پروژه خاص آماده شده توسط خود فیسبوک استفاده کرده ایم، بنابراین این کار به صورت خودکار برای ما انجام می شود. سپس در همین فایل کد زیر را اضافه می کنیم:
import React from 'react'; import TodoList from './components/TodoList'; const App: React.FC = () => { return <div className="App"> <TodoList /> </div> }; export default App;
بنابراین کار خاصی نکرده ایم و فقط مثل همیشه از کامپوننت خود به صورت کد JSX استفاده نموده ایم. با اجرای این کد در مرورگر، خروجی زیر را دریافت خواهیم کرد:
مشکل اینجاست که در برنامه های واقعی باید بتوانیم todo های بیشتری را به برنامه اضافه کنیم (این کامپوننت معمولا درون App.tsx قرار می گیرد) بنابراین بهتر است آرایه todos را درون app.tsx بگذاریم:
const App: React.FC = () => { const todos = [{ id: 't1', text: 'Finish the course' }]; return ( <div className="App"> {/* A component that adds todos */} <TodoList items={todos} /> </div> ); };
همانطور که گفتم در برنامه ای واقعی تر todo ها بعدا از سمت کاربر اضافه می شوند (و معمولا از سمت پایگاه داده دریافت می شوند) بنابراین به احتمال زیاد به app.tsx می رسند. من در بالا قسمتی را به عنوان کامنت قرار داده ام که باید به جای آن کامپوننتی قرار داده شود که مسئول اضافه کردن todo ها باشد. در نهایت todos را به صورت prop به کامپوننت TodoList پاس داده ام.
با اجرای کد بالا و کامپایل شدن کدهای تایپ اسکریپت به خطا برمی خوریم. چرا؟ زمانی که در react از تایپ اسکریپت استفاده می کنیم، باید در مورد تمام تایپ های استفاده شده واضح عمل کنید. به عبارت دیگر اگر قرار است از prop ها استفاده کنیم باید به تایپ اسکریپت بگوییم که نوع داده هایشان چطور است و چه ساختاری دارند. برای حل کردن این مشکل ابتدا باید به کامپوننت TodoList بگوییم که باید props هایی را قبول کند و از طرفی آرایه todos نیز به فایل App.tsx منتقل شده است بنابراین وجود ندارد. با این حساب در فایل TodoList.tsx به جای کد زیر:
<ul> {todos.map(todo => <li key={todo.id}>{todo.text}</li>)} </ul>
می گوییم:
<ul> {props.items.map(todo => <li key={todo.id}>{todo.text}</li>)} </ul>
بحث اصلی اینجاست که حتی با نوشتن کدهای بالا نیز تایپ اسکریپت با ما همراهی نمی کند چرا که به تایپ اسکریپت نگفته ایم props ما قرار است یک خصوصیت به نام items داشته باشد. راه حل در کد زیر است:
const TodoList: React.FC = props => {
React.FC یک generic type است بنابراین می توانیم خودمان خصوصیات آن را مشخص کنیم. برای این کار یک interface جداگانه تعریف می کنم تا کارمان تمیز تر باشد:
import React from 'react'; interface TodoListProps { items: {id: string, text: string}[]; }; const TodoList: React.FC<TodoListProps> = props => { return ( <ul> {props.items.map(todo => ( <li key={todo.id}>{todo.text}</li> ))} </ul> ); }; export default TodoList;
همانطور که در TodoListProps می بینید prop های ما قرار است items را داشته باشند و این items یک id و یک text خواهند داشت. همچنین علامت [] هم مثل همیشه یعنی آرایه ای از این اشیاء را خواهیم داشت. در نهایت TodoListProps را به React.FC می دهیم تا generic type را کامل کنیم. با ذخیره این فایل کدهای ما کامپایل شده و دوباره نتیجه صحیح را در مرورگر خودمان مشاهده خواهیم کرد.
با استفاده از تایپ اسکریپت می توانیم جلوی مشکلات بسیاری در react را بگیریم. مثلا فرض کنید در برنامه بزرگی هستید و یادتان می رود که prop پاس داده شده به TodoList نام items را دارد و به جایش کد زیر را می نویسید:
<TodoList todos={todos} />
اگر از تایپ اسکرپیت استفاده کرده باشید به سرعت و در همان لحظه خطایی خواهید گرفت که todos برای چنین کامپوننتی وجود ندارد. به همین دلیل کدنویسی بسیار راحت تر می شود.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.