روحالله در حال ساخت یک اپلیکیشن جدید است. او سعی دارد استیتهای گلوبال اپلیکیشن خود را با کانتکست بنویسد، اما چون تنبل است، دوست ندارد هر بار این عمل را تکرار کند. تابعی به نام `createGlobalState` بنویسید که با گرفتن دستوراتی، این کار را برای او انجام دهد.
## جزئیات پروژه
پروژهی اولیه را از [این لینک](/contest/assignments/38422/download_problem_initial_project/134191/) دانلود کنید.
<details class="green">
<summary>
ساختار فایلهای پروژه
</summary>
```
context-maker
├── package.json
├── package-lock.json
├── public
│ └── index.html
├── README.md
└── src
├── App.js
├── contexts
│ └── count.js
├── index.js
├── lib
│ └── <mark title="شما تنها مجاز به اعمال تغییرات در این فایل هستید.">createGlobalState.js</mark>
└── __tests__
└── sample.test.js
```
</details>
<details class="brown">
<summary>
راهاندازی پروژه
</summary>
- پروژهی اولیه را دانلود و از حالت فشرده خارج کنید.
- با اجرای دستور `npm i` پکیجهای مورد نیاز را نصب کنید.
- با اجرای دستور `npm start` میتوانید پروژه را اجرا کنید، اما توجه داشته باشید که تا قبل از تکمیل فایل `src/lib/createGlobalState.js`، پروژه به درستی نمایش داده نمیشود.
</details>
تابع `createGlobalState` هر بار که روحالله بخواهد استیتی را با کانتکست ایجاد کند باید قابل استفاده باشد.
مثلاً اگر روح الله بخواهد استیتی به نام `count` را با کانتکست ایجاد کند، باید به شکل زیر بتواند این کار را انجام دهد:
```js src/contexts/count.js react
import { createGlobalState } from "../lib/createGlobalState";
const [CountProvider, useCount] = <mark title="تابعی که شما باید پیادهسازی کنید">createGlobalState</mark>((set) => ({
count: 0,
increment(num) {
set((count) => count + num);
},
decrementByOne() {
set((count) => count - 1);
},
backToZero() {
set(0);
},
}));
export { CountProvider, useCount };
```
تابع `createGlobalState` بهعنوان ورودی باید یک تابع بپذیرد. تابع ورودی نیز باید یک تابع دیگر به نام `set` دریافت کند.
تابعی که به `createGlobalState` پاس داده میشود باید یک آبجکت برگرداند که شامل نام استیت با مقدار اولیهی دلخواه و تعدادی تابع بهمنظور ایجاد تغییر در استیت باشد.
تضمین میشود که در هر بار استفاده از `createGlobalState`، آبجکت فوق فقط دارای یک استیت باشد و مابقی پراپرتیها توابعی برای تغییر همان استیت باشند.
توابعی که برای تغییر استیت تعریف میشوند باید بتوانند با استفاده از تابع `set` مقدار استیت را تغییر دهند.
**نکته:** تابع `set` دقیقاً مانند `setter` هوک `useState` رفتار میکند.
خروجی تابع `createGlobalState` باید یک آرایه باشد که این آرایه بهترتیب شامل یک کامپوننت `Provider` و یک هوک است.
کامپوننت `Provider` باید یک آبجکت، مشابه همان آبجکتی که در `createGlobalState` قرار دادیم را در قالب `Context` در دسترس فرزندانش قرار دهد.
فرزندان کامپوننت `Provider` باید بتوانند با استفاده از هوکی که از آرایهی خروجی تابع `createGlobalState` دریافت میکنیم از مقدار `Context` استفاده کنند.
مثالی از نحوهی استفاده از کامپوننت `Provider`:
```jsx index.js react
import ReactDOM from "react-dom";
import App from "./App";
import { CountProvider } from "./contexts/count";
ReactDOM.render(
<CountProvider>
<App />
</CountProvider>,
document.getElementById("root")
);
```
روحالله باید مجبور باشد از `Provider` مخصوص هر کانتکست استفاده کند. در غیر اینصورت، باید یک ارور جدید از نوع آبجکت `Error` دریافت کند که باعث توقف در ادامه اجرای برنامه شود.
برای مثال اگر او بدون استفاده از `CountProvider` سعی کند از هوک `useCount` استفاده کند، باید چنین اروری را دریافت کند:
```
The 'count' global state must be used within it's relevant context provider
```
**نکته:** متن دقیق ارور مهم نیست، اما حتماً باید شامل نام استیت باشد.
روحالله باید بتواند با استفاده هوکی که از آرایهی خروجی تابع `createGlobalState` دریافت میکند بهشکل زیر از مقدار استیت و توابعی که تعریف کرده بود استفاده کند:
```jsx App.js react
import { useCount } from "./contexts/count";
function App() {
<mark>const {count, increment, decrementByOne, backToZero} = useCount();</mark>
return (
<div>
<h1>{<mark>count</mark>}</h1>
<div>
<button onClick={() => <mark>increment(5)</mark>}>
Increment by 5
</button>
<button onClick={() => <mark>decrementByOne()</mark>}>
Decrement by 1
</button>
<button onClick={() => <mark>backToZero()</mark>}>Back To Zero</button>
</div>
</div>
);
}
export default App;
```
**نکته:** بدیهی است که مثال `count` بالا فقط یک نمونه از نحوهی کار تابع `createGlobalState` است. شما باید این تابع را طوری پیادهسازی کنید که با ورودیهای متفاوت از جمله تفاوت در نام استیت، مقدار اولیهی استیت و توابع مربوط به تغییر در استیت به درستی عمل کند.
**توجه:** شما تنها مجاز به اعمال تغییرات در فایل `src/lib/createGlobalState.js` هستید.
## آنچه باید آپلود کنید
پس از پیادهسازی موارد خواستهشده، پوشهی `src` را زیپ کرده و آپلود کنید.