مدیریت حالت در Svelte — آموزش Svelte (بخش دوم)
در Svelte هر کامپوننت علاوه بر تعریف markup ،CSS و منطق جاوا اسکریپت، میتواند حالت (State) خاص خود را میزبانی کند. حالت به هر دادهای گفته میشود که کامپوننت برای رندر کردن محتوایش به آن نیاز دارد. برای نمونه اگر در فیلد ورودی یک فرم دارای رشته test باشد، باید متغیری باشد که این مقدار را نگهداری کند. این همان حالت فیلد ورودی است. یا اگر فیلدی انتخاب شده باشد، یک متغیر در جایی این مسئله را ثبت میکند. اینها همگی جزئی از حالت هستند. بنابراین در این مقاله به توضیح روش مدیریت حالت در Svelte می پردازیم. برای مطالعه بخش قبلی این مجموعه مقالات آموزشی روی لینک زیر کلیک کنید:
حالت در Svelte
حالت در بخش script یک کامپوننت ذخیره میشود:
1<script>
2let count = 0
3</script>
اگر سابقه کار با فریمورکهای فرانتاند مانند Vue یا React را داشته باشید، شاید از خود بپرسید چطور میتوان این مقادیر را بهروزرسانی کرد؟ دلیل این مسئله آن است که آن فریمورکها این کار را به روشی نسبتاً غیر سرراست انجام میدهند. یک نکته عالی در مورد Svelte این است که برای بهروزرسانی حالت یک کامپوننت نیاز به انجام کار خاصی نیست. تنها کاری که باید انجام داد، انتساب است. برای نمونه میتوانید از یک انتساب ساده جاوا اسکریپت با استفاده از عملگر = استفاده کنید.
فرض کنید یک متغیر به نام count دارید. میتوانید آن را با استفاده از کد زیر افزایش دهید:
1count = count + 1
یا میتوانید از کد زیر استفاده کنید:
1count++
نمونه کد به صورت زیر است:
1<script>
2let count = 0
3
4const incrementCount = () => {
5 count++
6}
7</script>
8
9{count} <button on:click={incrementCount}>+1</button>
اگر با طرز کار مدیریت حالت از سوی فریمورکهای وب مدرن آشنا هم نباشید، درک طرز کار کد فوق موجب بروز مشکل چندانی برای شما نخواهد شد. Vue از یک رویکرد ساختیافتهتر با استفاده از کلاسها و مشخصه data بهره میگیرد. اگر از هر دوی این فریمورکها استفاده کرده باشید، متوجه میشوید که Svelte ساختاری بسیار شبیهتر به جاوا اسکریپت دارد.
البته باید به یک نکته توجه داشته باشیم که به سرعت آموخته میشود: در زمان تغییر دادن یک مقدار نیز باید از انتساب استفاده کنیم. Svelte همواره به انتساب نیاز دارد، در غیر این صورت ممکن است تشخیص ندهد که حالت تغییر یافته است. برای مقادیر ساده مانند رشتهها و اعداد، این وضعیت عموماً به صورت پیشفرض وجود دارد، زیرا همه متدهای رشتهها، یک رشته جدید بازگشت میدهند و در مورد اعداد نیز برخی به این روش عمل میکند و از این رو «تغییرناپذیر» (immutable) هستند.
در مورد آرایهها نمیتوانیم از متدهایی که آرایهها را تغییر میدهند مانند ()push() ،pop() ،shift() ،splice استفاده کنیم، زیرا هیچ انتسابی وجود ندارد. آنها ساختارهای درونی خود را تغییر میدهند، اما Svelte نمیتواند این را تشخیص دهد. با این حال همچنان میتوان از آنها استفاده کرد، ولی پس از اجرای عملیات باید متغیر را مجدداً به خودش انتساب دهیم. به مثال زیر توجه کنید:
1let list = [1, 2, 3]
2list.push(4)
3list = list
مثال فوق کمی سردرگمکننده است، اما آن را به سرعت به خاطر میسپارید. همچنین میتوانید از عملگر spread برای اجرای عملیات استفاده کنید:
1let list = [1, 2, 3]
2list = [...list, 4]
واکنشپذیری Svelte
در Svelte میتوانیم به تغییرهای رخ داده در حالت کامپوننت گوش دهیم و متغیرهای دیگر را بهروزرسانی کنیم. برای نمونه اگر یک متغیر count داشته باشیم:
1<script>
2let count = 0
3</script>
و با کلیک کردن یک دکمه آن را بهروزرسانی کنیم:
1<script>
2let count = 0
3
4const incrementCount = () => {
5 count = count + 1
6}
7</script>
8
9{count} <button on:click={incrementCount}>+1</button>
میتوانیم با استفاده از ساختار خاص :$ که یک بلوک جدید تعریف میکند، به تغییرات رخ داده روی count گوش کنیم. در این حالت هر زمان که متغیر ارجاع یافته تغییر پیدا کند، Svelte بلوک فوق را مجدداً اجرا میکند. به مثال زیر توجه کنید:
1<script>
2let count = 0
3
4const incrementCount = () => {
5 count = count + 1
6}
7
8$: console.log(`${count}`)
9</script>
10
11{count} <button on:click={incrementCount}>+1</button>
ما از بلوک زیر استفاده میکنیم:
1$: console.log(`${count}`)
میتوانید بیش از یکی از آنها را بنویسید:
1<script>
2$: console.log(`the count is ${count}`)
3$: console.log(`double the count is ${count * 2}`)
4</script>
همچنین میتوانید یک بلوک برای گروهبندی بیش از یک گزاره اضافه کنید:
1<script>
2$: {
3 console.log(`the count is ${count}`)
4 console.log(`double the count is ${count * 2}`)
5}
6</script>
ما از یک فراخوانی ()console.log استفاده کردیم، اما شما میتوانید متغیرهای دیگر را نیز بهروزرسانی کنید:
1<script>
2let count = 0
3let double = 0
4
5$: {
6 console.log(`the count is ${count}`)
7 double = count * 2
8 console.log(`double the count is ${double}`)
9}
10</script>
Props در Svelte
میتوان یک کامپوننت Svelte را با استفاده از ساختاری مانند زیر در هر کامپوننت دیگر ایمپورت کرد:
1import ComponentName from 'componentPath'
به مثال زیر توجه کنید:
1<script>
2import SignupForm from './SignupForm.svelte';
3</script>
مسیر نسبت به مسیر کامپوننت نسبی است. معنی /. این است که پوشه همان پوشه است. میتوان از /.. برای رفتن به یک پوشه بالاتر و همین طور تا آخر استفاده کرد. زمانی که این کار را انجام دادید، میتوانید از کامپوننت ایمپورت شده اخیر در markup مانند یک تگ HTML استفاده کنید:
1<SignupForm />
بدین ترتیب یک رابطه والد/فرزند بین دو کامپوننت شکل میگیرد که یکی ایمپورت میکند و دیگری ایمپورت میشود. در اغلب موارد میخواهیم که کامپوننت والد دادهها را به کامپوننت فرزند ارسال کند. این کار با استفاده از props میسر است. props خصوصیاتی شبیه به HTML معمولی دارد و یک شکل یکطرفه از ارتباط محسوب میشود. در این مثال ما یک prop به نام disabled ارسال میکنیم و در آن مقدار true را میفرستیم:
1<SignupForm disabled={true}/>
در کامپوننت SignupForm باید prop به نام disabled را به صورت زیر اکسپورت کرد:
1<script>
2 export let disabled
3</script>
این روشی برای بیان این واقعیت است که prop به کامپوننتهای والد عرضه شده است. زمانی که از این کامپوننت استفاده میکنید، میتوانید یک متغیر به جای یک مقدار ارسال کنید تا آن را به صورت دینامیک تغییر دهید:
1<script>
2import SignupForm from './SignupForm.svelte';
3let disabled = true
4</script>
5
6<SignupForm disabled={disabled}/>
زمانی که مقدار متغیر disabled تغییر مییابد، کامپوننت فرزند با مقدار prop جدید بهروزرسانی میشود. به مثال زیر توجه کنید:
1<script>
2import SignupForm from './SignupForm.svelte';
3let disabled = true
4setTimeout(() => { disabled = false }, 2000)
5</script>
6
7<SignupForm disabled={disabled}/>