# پروژه اولیه
پروژهی اولیه را از
[این لینک](/problemset/assignments/4367/download_problem_initial_project/132255/)
دانلود کنید.
ساختار فایلهای این پروژه به صورت زیر است.
<details class="green">
<summary>
ساختار پروژه
</summary>
```
use-page-data
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── hooks
│ │ └── usePageData.js
│ ├── App.js
│ ├── index.css
│ └── index.js
└── package.json
```
</details>
<details class="brown">
<summary>
راهاندازی پروژه
</summary>
**برای اجرای پروژه، باید `NodeJS` و `npm` را از قبل نصب کرده باشید.**
- ابتدا پروژهی اولیه را دانلود و از حالت فشرده خارج کنید.
- در پوشهی `use-page-data` ، دستور `npm install` را برای نصب نیازمندیها اجرا کنید.
- در همین پوشه، دستور `npm start` را برای راهاندازی پروژه اجرا کنید.
- پس از انجام موفق این مراحل، با مراجعه به آدرس `http://localhost:3000/`
میتوانید نتیجه را ببینید.
</details>
# جزئیات
ظاهر کلی برنامه بهاین صورت است:
![ظاهر برنامه](https://quera.ir/qbox/view/SuztAPWIlP/usePageData.gif)
از آنجایی که تعداد محصولات دیجیکالا در حال زیاد شدن است، ساخت *Custom Hook*
به یک بخش جدانشدنی از پروژهها تبدیل شده است.
ساختار *api* ها در دیجیکالا در تمام پروژهها رعایت شده است.
این موضوع باعث میشود ساخت یک *Custom Hook* برای ارسال درخواستها به سرور
بسیار مفید باشد.
در این سوال از شما میخواهیم یک *Custom Hook* به این منظور پیادهسازی کنید.
این هوک باید ورودیهای زیر را دریافت کند:
```json
{
"url": string,
"fireOnLoad": boolean,
"successCallback": (data) => void,
"failedCallback": () => void,
}
```
- `url`: این پارامتر آدرس *api* را مشخص میکند. بهعبارتی دیگر شما باید به این آدرس درخواست را ارسال کنید.
- `fireOnLoad`: این پارامتر مشخص میکند که آیا درخواست در هنگام ایجاد کامپوننت (*mount*) ارسال شود یا خیر.
- `successCallback`: این پارامتر یک *callback function* ،است و درصورتی که درخواست با موفقیت تمام شد باید صدا زده شود. پارامتر ورودی این تابع، پاسخ سرور است.
- `failedCallback`: این پارامتر یک *callback function* است و درصورتی که درخواست ناموفق بود، باید صدا زده شود.
خروجی هوک باید به شکل زیر باشد:
```json
{
"pending": boolean,
"hasError": boolean,
"data": any,
"request": () => Promise<any>,
}
```
- `pending`: نشاندهندهی آن است که درخواست به سرور فرستاده شده است ولی هنوز پاسخی از سرور دریافت نشده است.
- `hasError`: نشاندهندهی ناموفق بودن درخواست ارسالی است.
- `request`: یک تابع *async* برای ارسال درخواست است.
این تابع بخش اصلی هوک است.
در صورت موفقبودن درخواست این تابع باید پاسخ را برگرداند (*resolve*).
این تابع را میتوان به صورت جداگانه نیز صدا کرد.
- `data` : پاسخ سرور در این فیلد قرار داده میشود.
همچنین این هوک باید قابلیت کشکردن درخواستها را درصورت موفقیتآمیز بودن ریکوئست داشته باشد؛ بهاینصورت که برای هر *url* وضعیت درخواست را ذخیره کند و در درخواستهای بعدی به آن *url* از کش بخواند و درخواست جدیدی ارسال نکند.
بهعنوان مثال اگر هوک در چند جای مختلف استفاده شود یا اگر متد *request* چند بار برای یک *url* فراخوانی شود تنها یک ریکوئست به *url* داده شده زده میشود و پاسخ سرور برای بقیه ریکوئستها با *url* یکسان استفاده میگردد.
ساختار کش را میتوانید هرطور که خواستید پیاده سازی کنید به طور مثال این ساختار میتواند برای هر *url* به شکل زیر باشد:
```json
{
"hasError": boolean,
"result": any,
}
```
#### مواردی که باید در این سوال رعایت کنید:
- در صورتی که مقدار `fireOnLoad` برابر `true` باشد، باید تابع *request* در هنگام *mount* شدن کامپوننت صدا زده شود.
- درصورت وجود یک *url* در کش، درخواست جدیدی به آن *url* نباید ارسال شود.
- شرایط گفته شده باید برای هنگامی که *url* در کش موجود است نیز برقرار باشد.
- باید بتوان توسط تابع *request* به پاسخ سرور پس از *resolve* شدن دسترسی داشت.
#### تغییرات لازم برای هر فایل:
- فایل `usePageData.js`: موارد خواسته شده باید در این فایل قرار داده شوند.
# نکات
- شما تنها مجاز به اعمال تغییرات در فایل `usePageData.js` هستید.
- فرض کنید تمام درخواستهای *GET* میباشند.
- برای ارسال پاسخ فقط فایل `usePageData.js` ارسال کنید.