کلاس مشاهده گر

Observer ابزاری است که به شما امکان می دهد متغیرهای استیت سراسری خود را مقداردهی کرده و آنها را از هر نقطه در برنامه خود به روز کنید.

با استفاده از Observer، علاوه بر به روز رسانی مقادیر استیت، می توانید به تغییرات مقادیر گوش دهید تا در صورت تغییر آنها از آن مطلع شوید.

به طور پیش فرض، Rosma از یک نمونه از کلاس Observer استفاده می کند. با این حال، می توانید از چندین نمونه از کلاس Observer برای مدیریت بهتر پروژه خود استفاده کنید. در بخش های بعدی این موضوع توضیح داده خواهد شد.

کلاس Observer چندین متد ارائه می دهد که در زیر لیست شده است:

observer.get

متد observer.get برای دریافت مقادیر از استیت استفاده می شود. می توانید از این متد برای دریافت یک یا چند مقدار به طور همزمان استفاده کنید.

دریافت یک مقدار

برای دریافت فقط یک مقدار از استیت، باید کلید متغیر را به عنوان آرگومان به متد get ارسال کنید.

برای مثال، فرض کنید مقدار foo در استیت برابر با 'bar' باشد. در این حالت می توانید مقدار foo را دریافت کرده و به صورت زیر به متغیری اختصاص دهید:

import { observer } from 'rosma'; const foo = observer.get('foo'); console.log(foo); // bar
import { observer } from 'rosma'; const foo: string = observer.get('foo'); console.log(foo); // bar

دریافت چند مقدار به صورت همزمان

اگر می خواهید بیش از یک مقدار را از استیت دریافت کنید، باید کلیدهای مورد نظر را به عنوان یک آرایه به متد get ارسال کنید. در این حالت مقدار برگشتی از متد get یک آبجکت میباشد.

برای مثال، فرض کنید استیت ما حاوی مقادیر foo برابر با 'bar' و baz برابر با 'qux' باشد. برای بازیابی همزمان مقادیر foo و baz می توانید از کد زیر استفاده کنید:

import { observer } from 'rosma'; const values = observer.get(['foo', 'baz']); console.log(values); // { foo: 'bar', baz: 'qux' }
import { observer } from 'rosma'; type State = { foo: string; baz: string; }; const values = observer.get<State>(['foo', 'baz']); console.log(values); // { foo: 'bar', baz: 'qux' }

همچنین در نظر داشته باشید که می توانید مانند مثال زیر مقادیر شیء برگشتی را استخراج کنید تا هر مقدار را به یک متغیر جداگانه اختصاص دهید:

import { observer } from 'rosma'; const { foo, baz } = observer.get(['foo', 'baz']); console.log(foo, baz); // 'bar', 'qux'
import { observer } from 'rosma'; type State = { foo: string; baz: string; }; const { foo, baz } = observer.get<State>(['foo', 'baz']); console.log(foo, baz); // 'bar', 'qux'

observer.set

متد set برای تغییر یا اضافه کردن یک یا چند مقدار در استیت استفاده می شود. هنگامی که یک مقدار در استیت با استفاده از متد set تغییر می‌کند، همه کامپوننت هایی که از آن مقدار استفاده می‌کنند rerender می‌شوند. با این حال، این امکان نیز وجود دارد که یک مقدار را به صورت بی صدا تغییر دهید، بدون اینکه کامپوننت هایی که از آن استفاده می کنند، rerender شوند .

توجه داشته باشید که اگر مقداری را به‌صورت بی‌صدا تنظیم کنید، و کامپوننتی که از آن مقدار استفاده می‌کند، بعداً به دلایل دیگر rerender شود، مقدار جدید از استیت دریافت می‌شود.

پیش نمایش

import { observer, useObserver } from 'rosma'; export function DisplayTime() { const { time, setTime } = useObserver(''); return ( <div> <p>Time is: {time}</p> <Button onClick={() => setTime(getTime())}> Update time with setter method </Button> <Button onClick={() => observer.set({ time: getTime() })}> Update time with observer.set </Button> <Button onClick={() => observer.set({ time: getTime() }, { silent: true })} > Update time silently </Button> </div> ); } function getTime() { return new Date().toLocaleTimeString(); } function Button(props) { return <button {...props} style={{ display: 'block' }} />; }
import { observer, useObserver } from 'rosma'; type State = { time: string; }; export function DisplayTime() { const { time, setTime } = useObserver<State>(''); return ( <div> <p>Time is: {time}</p> <Button onClick={() => setTime(getTime())}> Update time with setter method </Button> <Button onClick={() => observer.set<State>({ time: getTime() })}> Update time with observer.set </Button> <Button onClick={() => observer.set<State>({ time: getTime() }, { silent: true }) } > Update time silently </Button> </div> ); } function getTime() { return new Date().toLocaleTimeString(); } function Button(props) { return <button {...props} style={{ display: 'block' }} />; }

Time is:


در این مثال، کامپوننت DisplayTime مقدار زمان را از استیت موجود در observer با استفاده از هوک useObserver دریافت می کند و آن را در یک پاراگراف نمایش می دهد.

این کامپوننت همچنین شامل سه دکمه است که به کاربر امکان می دهد مقدار زمان را به روش های مختلف به روز کند. اولین دکمه متد setTime را برای به روز رسانی مقدار با استفاده از هوک useObserver فراخوانی می کند. دکمه دوم متد observer.set را فراخوانی می کند تا مقدار را مستقیماً در استیت موجود در observer به روز کند. دکمه سوم متد observer.set را با گزینه silent فراخوانی می‌کند تا مقدار را به‌طور بی‌صدا به‌روزرسانی کند، بدون اینکه هیچ کامپوننتی که از مقدار زمان استفاده می‌کند را rerender کند.

یک مثال از کامپوننت مودال

این کد یک مثال ساده و کاربردی از نحوه استفاده از متد های get و set در observer است. استفاده از این متد ها به کاربر این اجازه را می دهد تا کامپوننت مودال را باز و بسته کند و آنها را در در سرتاسر برنامه نمایش دهد.

export type Modal = { title: string; body: string; id?: number; }; export type State = { modals: Modal[]; };

app.tsx

کامپوننت App نقطه ورود برنامه است. آن شامل دکمه ای است که باعث ایجاد شدن یک مودال جدید میشود و کامپوننت Modals وظیفه render کردن تمامی مودال های باز را دارد. تابع newModal از actions.ts ایمپورت شده تا ایجاد شدن مودال جدید را مدیریت کند.

import Modals from './modals'; import { newModal } from './actions'; export function App() { return ( <> <button onClick={() => newModal({ title: 'Modal title', body: 'Modal body' })} > Open Modal </button> <Modals /> </> ); }
import Modals from './modals'; import { newModal } from './actions'; export function App() { return ( <> <button onClick={() => newModal({ title: 'Modal title', body: 'Modal body' })} > Open Modal </button> <Modals /> </> ); }

modals.tsx

کامپوننت Modals از هوک useObserver برای دریافت آرایه modals از استیت استفاده می کند، که داده ها را برای هر مدال باز نگه می دارد. با استفاده از تابع map میتوان تمامی مودال های موجود را توسط کامپوننت Modal نمایش داد . کامپوننت Modal مسئول رندر مدال ها با title ، body و یک دکمه close میباشد.

import { useObserver } from 'rosma'; import { closeModal } from './actions'; export default function Modals() { const { modals } = useObserver([]); return modals.map((modal, index) => <Modal key={index} {...modal} />); } function Modal({ title, body, id }) { return ( <div style={{ backgroundColor: 'white', boxShadow: '0 0 5px #ccc', minWidth: '300px', position: 'fixed', left: '50%', top: '50%', transform: 'translate(-50%, -50%)', borderRadius: '7px', }} > <div style={{ display: 'flex', padding: '10px', borderBottom: '1px solid #ccc', gap: '5px', }} > <span>{title}</span> <span>#{id}</span> <div style={{ flex: 1 }} /> <button onClick={() => closeModal(id)}>x</button> </div> <div style={{ padding: '10px' }}>{body}</div> </div> ); }
import { useObserver } from 'rosma'; import { closeModal } from './actions'; import { Modal, State } from './types'; export default function Modals() { const { modals } = useObserver<State>([]); return ( <> {modals.map((modal, index) => ( <Modal key={index} {...modal} /> ))} </> ); } function Modal({ title, body, id }: Modal) { return ( <div style={{ backgroundColor: 'white', boxShadow: '0 0 5px #ccc', minWidth: '300px', position: 'fixed', left: '50%', top: '50%', transform: 'translate(-50%, -50%)', borderRadius: '7px', }} > <div style={{ display: 'flex', padding: '10px', borderBottom: '1px solid #ccc', gap: '5px', }} > <span>{title}</span> <span>#{id}</span> <div style={{ flex: 1 }} /> <button onClick={() => closeModal(id)}>x</button> </div> <div style={{ padding: '10px' }}>{body}</div> </div> ); }

actions.ts

فایل action دو تابع newModal و closeModal را export می کند. هر دوی این توابع از نمونه observer ارائه شده توسط کتابخانه Rosma برای بدست آوردن و تنظیم آرایه modals در استیت سراسری استفاده می کنند. تابع newModal یک شی مودال جدید با id ، title و body منحصر به فرد ایجاد می کند و آن را به آرایه modals اضافه می کند. تابع closeModal مودال را با شناسه داده شده از آرایه modals فیلتر می کند.

import { observer } from 'rosma'; export function newModal({ title, body }) { const modals = observer.get('modals') || []; const modal = { id: modals.length + 1, title, body, }; modals.push(modal); observer.set({ modals }); } export function closeModal(id) { const modals = observer.get('modals') || []; observer.set({ modals: modals.filter((modal) => modal.id !== id) }); }
import { observer } from 'rosma'; import { Modal, State } from './types'; export function newModal({ title, body }: Modal) { const modals: Modal[] = observer.get('modals') || []; const modal: Modal = { id: modals.length + 1, title, body, }; modals.push(modal); observer.set<State>({ modals }); } export function closeModal(id: number) { const modals: Modal[] = observer.get('modals') || []; observer.set<State>({ modals: modals.filter((modal) => modal.id !== id) }); }

پیش نمایش

observer.state

مقدار فعلی استیت را برمی‌گرداند.

همانطور که قبلا ذکر شد، همه متغیرهای موجود در استیت با حروف کوچک ذخیره می شوند، در حالی که نام های بازیابی شده از مقادیر استیت به حروف بزرگ و کوچک حساس نیستند.

توجه داشته باشید که تغییر دادن استیت با استفاده از observer.state، کامپوننت ها را ری رندر نمی‌کند یا listener ها را اجرا نمی‌کند.

import { observer } from 'rosma'; observer.set({ foo: 'bar' }); console.log(observer.state.foo); // "bar"
import { observer } from 'rosma'; observer.set({ foo: 'bar' }); console.log(observer.state.foo); // "bar"

observer.isValid

observer.get بررسی می کند که آیا کلید داده شده در استیت وجود دارد یا خیر. یک استرینگ به عنوان کلید دریافت می کند و تعیین می کند که آیا آن متغیر در استیت تعریف شده است یا خیر.

import { observe } from 'rosma'; observer.isValid('myVariable'); // false observer.set({ myVariable: 'something' }); observer.isValid('myVariable'); // true
import { observe } from 'rosma'; observer.isValid('myVariable'); // false observer.set({ myVariable: 'something' }); observer.isValid('myVariable'); // true

observer.subscribe

متد subscribe برای نظارت بر تغییرات در یک یا چند متغیر در استیت استفاده می شود. این متد به دو پارامتر ورودی نیاز دارد:

  1. کلید یا کلیدهای مورد نظر که می خواهید تغییراتشان را نظرات کنید.

  2. یک listener که با تغییر کلید یا کلیدهای مورد نظر اجرا می شود.

این متد یک تابع unsubscribe را برمی‌گرداند و به شما امکان می‌دهد که در صورت نیاز نظرات بر تغییرات متغیر ها را غیر فعال کنید. بسته به نیاز شما می‌توان از این متد در داخل useEffect یا خارج از کامپوننت React استفاده کرد. اگر نیاز به نظارت بر تغییرات چندین متغیر به طور همزمان را دارید، می توانید آنها را به عنوان یک آرایه تعریف کنید و آن را به عنوان اولین پارامتر به متد subscribe ارسال کنید. البته توجه داشته باشید که در این حالت مقادیر مورد نظر به عنوان یک object به تابع listener ارسال می شود.

در بخش های بعدی بیشتر در مورد subscribe صحبت خواهیم کرد.

پیش نمایش



import { observer, useObserver } from 'rosma'; const unsubscribe = observer.subscribe('myVar', listener); function listener(myVar) { alert('myVar changed! ' + myVar); } export function ObserverTest() { const { setMyVar } = useObserver(); return ( <> <button onClick={() => setMyVar(new Date())}>Click me</button> <button onClick={unsubscribe}>Unsubscribe</button> </> ); }
import { observer, useObserver } from 'rosma'; type State = { myVar: Date; }; const unsubscribe = observer.subscribe<State>('myVar', listener); function listener(myVar: State['myVar']) { alert('myVar changed! ' + myVar); } export function ObserverTest() { const { setMyVar } = useObserver<State>(); return ( <> <button onClick={() => setMyVar(new Date())}>Click me</button> <button onClick={unsubscribe}>Unsubscribe</button> </> ); }

در این مثال observer و useObserver را از کتابخانه rosma ایمپورت کرده. سپس با فراخوانی observer.subscribe و ارسال نام متغیر myVar به عنوان پارامتر اول و تابع listener به عنوان پارامتر دوم، نظرات بر تغییرات متغیر myVar را شروع میکنیم.

کامپوننت ObserverTest از useObserver برای دریافت تابع setMyVar استفاده می کند که می تواند برای به روز رسانی مقدار myVar فراخوانی شود. آن کامپوننت دکمه ای را ارائه می کند که با کلیک کردن روی آن، setMyVar را با یک شیء تاریخ جدید به عنوان آرگومان اجرا می کند. هنگامی که myVar تغییر می کند، تابع listener فراخوانی می شود و یک هشدار با مقدار به روز شده myVar نمایش داده می شود.

اگر کاربر روی دکمه لغو اشتراک کلیک کند. متد لغو اشتراک اجرا می شود و تابع listener با تغییرات myVar دیگر فراخوانی نمی شود.

کلید واژه ها: observer, مقادیر استیت سراسری, بروزرسانی استیت, تظارت بر استیت, multiple instances, observer.get, observer.set, observer.isValid, observer.subscribe, دریافت مقادیر, گرفتن یک مقدار, گرفتن چند مقدار, تغییر یا اضافه کردن مقدار, بی‌صدا, پیش نمایش, کامپوننت مودال, app.tsx, modals.tsx

قبلی: هوک useObserver

بعدی: استفاده از چند مشاهده گر