مدیریت state در ری اکت و آموزش zustand
ری اکت یک کتابخانه جاوا اسکریپت برای توسعه وب اپلیکیشنهای تعاملی است. یکی از ویژگیهای اصلی ری اکت، مدیریت استیت (State Management) است. مدیریت وضعیت به توسعهدهندگان کمک میکند تا دادههای اپلیکیشن خود را بهطور منظم بروزرسانی کنند و تغییرات را در سراسر اپلیکیشن بهروزرسانی کنند.
در ری اکت، هر کامپوننت میتواند یک یا چند state داشته باشد. state دادههای داخلی کامپوننت است که میتواند در طول زمان تغییر کند. برای مدیریت state یک کامپوننت، میتوان از دو روش استفاده کرد:
- استفاده از توابع
state
وsetState()
- استفاده از کتابخانههای مدیریت وضعیت
استفاده از توابع state
و setState()
برای مدیریت state یک کامپوننت با استفاده از توابع state
و setState()
، باید state کامپوننت را بهعنوان یک ویژگی تعریف کنید. بهعنوان مثال، کامپوننتی با یک state ساده بهصورت زیر تعریف میشود:
import { useState } from "react";
const MyComponent = () => {
const [state, setState] = useState(0)
return (
<div>
<h1>State: {state}</h1>
<button onClick={() => setState(state+1)}>
افزایش شمارنده
</button>
</div>
);
};
export default MyComponent
در این کد، state
یک ویژگی است که مقدار اولیه آن با استفاده از پارامتر initialState
تعیین میشود. setState()
تابعی است که مقدار state را تغییر میدهد.
اما همیشه کار به این سادگی نیست. در برخی زمان ها، عموما نیاز داریم داده ها را در یک صفحه نگه داشته و آن را بین صفحات دیگر تقسیم کنیم.
در ری اکت ساختار های props و context این کار را تا قسمتی برای من انجام میدهند. اما استفاده از کتابخانه های مخصوص این کار، میتواند امکانات بیشتری به ما ارایه کند.
استفاده از کتابخانههای مدیریت state
کتابخانههای مدیریت state ، راهحلهای آمادهای برای مدیریت state ارائه میدهند. این کتابخانهها معمولاً امکانات بیشتری نسبت به استفاده مستقیم از توابع state
و setState()
ارائه میدهند.
برخی از کتابخانههای محبوب مدیریت وضعیت در ری اکت عبارتند از:
Redux
Redux یک کتابخانه مدیریت وضعیت کامل و انعطافپذیر است. Redux بر اساس مفهوم store کار میکند. store یک شیء است که state اپلیکیشن را در خود ذخیره میکند. برای تغییر مقدار state، باید یک action ایجاد کنید و آن را به store ارسال کنید.
Mobx
Mobx یک کتابخانه مدیریت وضعیت ساده و کارآمد است. Mobx بر اساس مفهوم observable کار میکند. observableها دادههایی هستند که بهطور خودکار بروزرسانی میشوند. برای تغییر مقدار state، میتوانید مقدار یک observable را تغییر دهید.
Context
Context یک API جدید در ری اکت 16.8 است. Context برای مدیریت state در سطح بالاتر استفاده میشود. برای استفاده از Context، باید یک provider و یک consumer ایجاد کنید. provider state را در خود ذخیره میکند و consumer میتواند از state استفاده کند.
کدام کتابخانه مدیریت state مناسب است؟
انتخاب کتابخانه مدیریت وضعیت مناسب به نیازهای اپلیکیشن شما بستگی دارد. اگر نیاز به یک کتابخانه مدیریت وضعیت کامل و انعطافپذیر دارید، Redux گزینه مناسبی است. اگر نیاز به یک کتابخانه مدیریت وضعیت ساده و کارآمد دارید، Mobx گزینه مناسبی است. اگر نیاز به مدیریت state در سطح بالاتر دارید، Context گزینه مناسبی است.
آموزش کتابخانه Zustand
Zustand یک کتابخانه مدیریت وضعیت برای ری اکت است که بر اساس مفهوم hook کار میکند. Zustand یک کتابخانه ساده و کارآمد است که برای اپلیکیشنهای کوچک و متوسط مناسب است.
Zustand یک کتابخانه مدیریت state مدرن برای React است که بر پایه Zustand Store و Zustand Hook بنا شده است.
Zustand دارای ویژگیهای زیر است:
- ساده و آسان برای استفاده: Zustand API بسیار ساده و قابل فهمی دارد.
- عملکرد بالا: Zustand برای ارائه عملکرد بالا طراحی شده است.
- قابل مقیاس: Zustand به راحتی می تواند با برنامه های بزرگ و پیچیده مقیاس بندی شود.
- قابل تست: Zustand به راحتی قابل تست است.
- جامعه فعال: Zustand دارای جامعه فعال و مفیدی است.
- موارد استفاده از Zustand:
- مدیریت state در کامپوننت های React
- مدیریت state در برنامه های React بزرگ و پیچیده
- اشتراک گذاری state بین کامپوننت های React
- ذخیره سازی state در حافظه محلی یا IndexedDB
Zustand بر اساس مفهوم hook کار میکند. hookها توابعی هستند که میتوان از آنها برای دسترسی به state و تغییر آن استفاده کرد. برای استفاده از Zustand، باید یک hook را برای state خود ایجاد کنید.
برای نصب کامند زیر:
npm install zustand
بزن بریم که شروع کنیم!
ابتدا باید یک فایل store.jsx بسازید و کد زیر را در آن قرار دهید.
import { create } from 'zustand'
const useStore = create((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}))
export default useStore
همانطور که میبینید، در استور یک استیت تعریف کرده و مقدار اولیه آن را صفر در نظر گرفته ایم. همچنین دو فانکشن در آن تعریف کردیم که یکی، افزاینده و دیگری معادل صفر میکند.
حال در فایل دیگری مانند master.jsx کد زیر را قرار دهید:
import useStore from './store'
function BearCounter() {
const bears = useStore((state) => state.bears)
return <h1>{bears} i am zustand ♥</h1>
}
function Controls() {
const increasePopulation = useStore((state) => state.increasePopulation)
return <button onClick={increasePopulation}>one up</button>
}
function Remove() {
const removeAllBears = useStore((state) => state.removeAllBears)
return <button onClick={removeAllBears}>reset</button>
}
export default function Main(){
return(
<>
<BearCounter />
<Controls />
<Remove />
</>
)
}
همانطور که در این کد میبینید، ابتدا در هر فایلی که میخواهیم از دیتا های store استفاده کنیم، آن را فراخوانی میکنیم. سپس همان دو فانکشنی که در صفحه استور معرفی کردیم را نوشته و آنها را تعیین وضعیت میکنیم. به راحتی دیتا ها بین صفحات جابجا میشوند.
تفاوت zustand و redux
از نظر مفهومی، Zustand و Redux کاملا مشابه هستند، هر دو بر اساس یک مدل immutable state هستند. با این حال، Redux نیاز دارد که برنامه شما در context , providers شود. اما زاستند اینطور نیست.
مثال عملی کار با زاستند
بعنوان مثال اول، اجازه بدهید یک استور بسازیم و در آن از یک api مقادیری را استخراج کرده و در صفحات دیگر از مقادیر آن استفاده کنید. پس کد زیر را در صفحه store بنویسید:
import { create } from 'zustand'
let data;
async function users() {
let response = await fetch('https://jsonplaceholder.typicode.com/todos');
data = await response.json();
};users()
const useStore = create((set) => ({
bears: [],
getData: () => set((state) => ({ bears: data })),
}))
export default useStore
و در ادامه در صفحه page ابتدا استور را فراخوانی کرده و از مقادیر استیت آن استفاده کنید:
import useStore from './store'
function BearCounter() {
const bears = useStore((state) => state.bears)
return (
<>
<h1>{console.log(bears)} i am zustand ♥</h1>
{bears.map((val)=>{
return(
<article key={val.id}>
<h2>{val.title}</h2>
</article>
)
})}
</>
)
}
function Controls() {
const getData = useStore((state) => state.getData)
return <button onClick={getData}>fetch data</button>
}
export default function Main(){
return(
<>
<BearCounter />
<Controls />
</>
)
}
در مثال بالا ما در استور مقادیری را استخراج کردیم و آن را بین صفحاتی که نیاز دیتا های آن دارند، فراخوانی کردیم.
اما در این مثال میخواهیم از صفحات دیگری، مانند صفحه page.jsx مقادیری را به سمت استور ارسال کرده و آن را آپدیت کنیم.
به همین منظور ابتدا با کد های زیر صفحه store را میسازیم:
import create from 'zustand';
const useUserStore = create((set) => ({
username: '',
age: 0,
updateUser: (newUsername, newAge) => set({ username: newUsername, age: newAge }),
}));
export default useUserStore;
و سپس در صفحه page.jsx مقادیری را به سمت آن ارسال کرده و آن را آپدیت میکنیم. کد زیر:
import React from 'react';
import useUserStore from './store';
const UserProfile = () => {
const { username, age, updateUser } = useUserStore();
return (
<div>
<h2>User Profile</h2>
<p>Username: {username}</p>
<p>Age: {age}</p>
<button onClick={() => updateUser('parsa ghorbanian', 32)}>Update User</button>
</div>
);
};
export default UserProfile;
به عنوان آخرین مثال، فرض بفرمایید که مقادیر دیتای ارسالی ما از یک صفحه، به Store زیاد و متنوع میباشد(مثلا محصولات یه فروشگاه). در این صورت کد زیر میتواند مقادیر ارسال شده از صفحات دیگربه استور را به استیت اصلی، push کند.
کد store:
import create from 'zustand';
const useUserStore = create((set) => ({
username: ['ali'],
updateUser: (e) => set((state) => ({ username: [...state.username, e.target.getAttribute('data-info')] })),
}));
export default useUserStore;
کد صفحه ارسال کننده فایل:
import React from 'react';
import useUserStore from './store';
const UserProfile = () => {
const { username, updateUser } = useUserStore();
return (
<div>
<h2>User Profile</h2>
<p>Username: {username[0]}</p>
<ul>
{username.map((val)=>{
return(
<li>{val}</li>
)
})}
</ul>
<button data-info='footabll' onClick={(e) => updateUser(e)}>Update User</button>
<button data-info='basketball' onClick={(e) => updateUser(e)}>Update User</button>
<button data-info='volleyball' onClick={(e) => updateUser(e)}>Update User</button>
<button data-info='golf' onClick={(e) => updateUser(e)}>Update User</button>
</div>
);
};
export default UserProfile;
و یا در مثالی دیگر استور ما میتواند بصورت حرفه ای ، اضافه حذف و آپدیت را داشته باشد. این کد استور را همیشه در نظر داشته باشید. با توضیحاتی که در بالا داده شد، این کد میتواند یک استور حرفه ای برای شما به ارمغان بیاورد.
import { create } from 'zustand'
const useCart = create((set) => ({
cart: [],
addToCart: (product) => set((state) => {
const existingProduct = state.cart.find((item) => item.id === product.id);
if (existingProduct) {
alert('exist..!');
return state;
} else {
return { cart: [...state.cart, product] };
}
}),
removeFromCart: (productId) => set((state) => ({
cart: state.cart.filter((item) => item.id !== productId)
})),
plusFromCart : (pId) => set((state)=>{
const index = state.cart.findIndex((item) => item.id === pId);
if (index !== -1) {
state.cart[index].num += 1;
return { cart: [...state.cart] };
}
})
}))
export default useCart
امیدواریم از این مقاله مدیریت state در ری اکت و آموزش zustand نهایت استفاده را برده باشید و آن را با دوستانتان به اشتراک بگذارید. تیم تولید محتوای مدرسه اینترنتی پرنیان این مقاله را تهیه کرده است.
درباره مدیریت
شما در حال مطالعه یکی از مقالات آموزشی وبلاگ پرنیان بودید. اگر برایتان مفید بود آن را با دوستانتان به اشتراک بگذارید. من پارسا قربانیان و اینجا مدرسه فرانت اند پرنیان، میخواهیم در یک معامله برد برد، با هم به آرزوهایمان برسیم..
نوشته های بیشتر از مدیریت2 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
مطالعه کردم-بسیار عاااااالی و به روز – تشکر استااااااد عزیز👌
سپاس از شما