جستجو برای:
  • خانه
  • دوره و کتاب
  • مقالات
    • خانواده جاوا اسکریپت
      • مقالات جاوا اسکریپت
      • مقالات ری اکت و نکست
      • هوش مصنوعی
    • خانواده فرانت
      • مقالات سی اس اس
      • مقالات اچ تی ام ال
    • محیط کار
      • سوالات استخدامی جاوا اسکریپت
      • سوالات استخدامی ری اکت
      • اصطلاحات محیط کار فرانت اند
    • مجله پرنیان
      • تصاویر دوره ها
      • نظرات دانشجویان قدیم
  • سوالات متداول
  • تماس با ما
  • خانواده پرنیان
    • چت خانه
    • دستیار هوش مصنوعی(رایگان!)
    • تایید مدارک
    • پیام یا انتقاد (ناشناس)
    • تعیین سطح زبان انگلیسی
    • پخش لایو رادیوسام
 
  • 09921632445
  • radioarsam[at]gmail.com
  • فروشگاه محصولات
  • بلاگ
  • تماس با ما
  • درباره پارسا قربانیان، موسس مدرسه پرنیان
پارسا قربانیان |گروه آموزشی پرنیان | آموزش حرفه ای طراحی سایت
  • خانه
  • دوره و کتاب
  • مقالات
    • خانواده جاوا اسکریپت
      • مقالات جاوا اسکریپت
      • مقالات ری اکت و نکست
      • هوش مصنوعی
    • خانواده فرانت
      • مقالات سی اس اس
      • مقالات اچ تی ام ال
    • محیط کار
      • سوالات استخدامی جاوا اسکریپت
      • سوالات استخدامی ری اکت
      • اصطلاحات محیط کار فرانت اند
    • مجله پرنیان
      • تصاویر دوره ها
      • نظرات دانشجویان قدیم
  • سوالات متداول
  • تماس با ما
  • خانواده پرنیان
    • چت خانه
    • دستیار هوش مصنوعی(رایگان!)
    • تایید مدارک
    • پیام یا انتقاد (ناشناس)
    • تعیین سطح زبان انگلیسی
    • پخش لایو رادیوسام
0

ورود و ثبت نام

بلاگ پرنیان

پارسا قربانیان |گروه آموزشی پرنیان | آموزش حرفه ای طراحی سایتبلاگمقالاتمقالات reactمدیریت state در ری اکت و آموزش zustand

مدیریت state در ری اکت و آموزش zustand

2 بهمن 1402
ارسال شده توسط مدیریت
مقالات ، مقالات react
1.34k بازدید
مدیریت state در ری اکت و آموزش zustand

ری اکت یک کتابخانه جاوا اسکریپت برای توسعه وب اپلیکیشن‌های تعاملی است. یکی از ویژگی‌های اصلی ری اکت، مدیریت استیت (State Management) است. مدیریت وضعیت به توسعه‌دهندگان کمک می‌کند تا داده‌های اپلیکیشن خود را به‌طور منظم بروزرسانی کنند و تغییرات را در سراسر اپلیکیشن به‌روزرسانی کنند.

در برنامه‌های مدرن تحت وب که با کتابخانه‌هایی مانند React توسعه داده می‌شوند، مدیریت وضعیت (State Management) یکی از مهم‌ترین چالش‌ها به شمار می‌رود. هر چه اندازه و پیچیدگی پروژه افزایش می‌یابد، اهمیت مدیریت صحیح وضعیت‌ها بین کامپوننت‌ها بیشتر احساس می‌شود.

به طور پیش‌فرض، React دارای سیستم مدیریت وضعیت داخلی (local state) برای هر کامپوننت است، اما این روش در پروژه‌های بزرگ پاسخ‌گوی نیازها نیست؛ زیرا اشتراک‌گذاری داده‌ها میان کامپوننت‌های غیرهم‌سطح یا پراکنده بسیار دشوار و پرهزینه می‌شود. اینجاست که کتابخانه‌هایی مانند Zustand وارد عمل می‌شوند.

در ری اکت، هر کامپوننت می‌تواند یک یا چند 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

چرا Zustand؟

Zustand (در زبان آلمانی به معنای “وضعیت”) یک کتابخانه‌ی سبک و مدرن برای مدیریت وضعیت در برنامه‌های React و Next.js است. برخلاف Redux که نیاز به boilerplate (کدهای تکراری و ساختاریافته‌ی زیاد) دارد، Zustand با طراحی ساده و روان، تجربه‌ای سریع‌تر و راحت‌تر را برای توسعه‌دهندگان فراهم می‌کند.

مزایای اصلی Zustand به اختصار:

  • سبک و سریع (فاقد وابستگی به context یا reducer)
  • نوشتار ساده و مستقیم
  • بدون نیاز به provider یا wrapper خاص
  • سازگار با SSR (در Next.js)
  • قابلیت استفاده از چندین store مجزا
  • دارای API مشابه React Hookها

آموزش کتابخانه 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
# یا
yarn add 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 شود. اما زاستند اینطور نیست.

مثال عملی کار با زاستند

بعنوان مثال اول، میخواهیم از صفحات دیگری، مانند صفحه 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

or///

  plus: (id) => {
    set((state) => {
      return {
        data: state.data.map(item => item.id === id ? {
          ...item, count:
            item.count + 1
        } : item)
      }
    })
  },
  minus: (id) => {
    set((state) => {
      return {
        data: state.data.map(item => item.id === id ? {
          ...item, count: (item.count > 1) && item.count - 1 } : item)
      }
    })
  },

مدیریت چند Store و ساختاردهی بهتر

در پروژه‌های متوسط تا بزرگ، نگهداری تمام وضعیت‌ها در یک Store واحد می‌تواند باعث شلوغی و کاهش خوانایی کد شود. برای حل این مشکل، می‌توانیم چندین Store جداگانه ایجاد کنیم و هر کدام را به یک حوزه‌ی خاص اختصاص دهیم (مانند کاربر، سبد خرید، تنظیمات، و غیره).

/store
  ├── useCounterStore.js
  ├── useUserStore.js
  └── useThemeStore.js

فایل useUserStore.js بسازید:

import { create } from 'zustand';

const useUserStore = create((set) => ({
  user: null,
  setUser: (userData) => set({ user: userData }),
  logout: () => set({ user: null }),
}));

export default useUserStore;

اکنون می‌توانید در هر کامپوننت، تنها Store مورد نیاز را وارد کرده و از آن استفاده کنید. این کار موجب جداسازی مسئولیت‌ها (Separation of Concerns) و بهبود نگهداری کد در طول زمان می‌شود.

استفاده از Zustand در Server-Side Rendering (SSR) در Next.js

استفاده از Zustand در پروژه‌های Next.js که از Server-Side Rendering (SSR) بهره می‌برند، نیاز به دقت بیشتری دارد؛ زیرا Zustand به‌صورت پیش‌فرض فقط در سمت کلاینت اجرا می‌شود. با این حال، می‌توان آن را به‌گونه‌ای پیکربندی کرد که با SSR نیز سازگار باشد.

Zustand از React Context استفاده نمی‌کند و به همین دلیل به‌صورت ذاتی بدون مشکل در کلاینت کار می‌کند. اما برای prepopulate کردن وضعیت (hydrate کردن) از سمت سرور، باید از روش‌هایی مانند initial state یا hydrate کردن دستی استفاده کرد. بعنوان مثال فرض کنیم اطلاعات کاربر را از سرور دریافت و در Store مقداردهی اولیه می‌کنیم.

const useUserStore = create((set) => ({
  user: null,
  setUser: (user) => set({ user }),
}));

در صفحه‌ی Next کد زیر:

export async function getServerSideProps(context) {
  const res = await fetch('https://api.example.com/user');
  const user = await res.json();

  return {
    props: {
      initialUser: user,
    },
  };
}

و در نهایت در کامپوننت صفحه کد زیر:

import { useEffect } from 'react';
import useUserStore from '../store/useUserStore';

export default function ProfilePage({ initialUser }) {
  const setUser = useUserStore((state) => state.setUser);

  useEffect(() => {
    setUser(initialUser);
  }, [initialUser, setUser]);

  const user = useUserStore((state) => state.user);

  return <div>سلام، {user?.name}</div>;
}

استفاده از تابع shallow برای مقایسه سطحی

برای جلوگیری از رندر مجدد هنگام استفاده از چند مقدار مختلف از Store، می‌توان از تابع shallow استفاده کرد مانند کد زیر:

import { shallow } from 'zustand/shallow';

const { count, name } = useUserStore(
  (state) => ({ count: state.count, name: state.name }),
  shallow
);

استفاده از حالت Lazy-loading یا dynamic imports

در صفحات Next.js که به Store خاصی نیاز دارند، می‌توان Store را به‌صورت دینامیک import کرد تا حجم initial bundle کاهش یابد مانند کد زیر:

const useCartStore = dynamic(() => import('../store/useCartStore'), { ssr: false });

ذخیره‌سازی وضعیت Zustand در Local Storage

در برخی مواقع، نیاز داریم داده‌های Zustand در مرورگر ذخیره شوند و پس از رفرش صفحه نیز باقی بمانند. این کار با استفاده از middleware مخصوص Zustand به‌راحتی ممکن است.

Zustand این قابلیت را از طریق middleware به نام persist فراهم می‌کند که اطلاعات state را در localStorage یا sessionStorage ذخیره می‌کند و هنگام بارگذاری مجدد، آن‌ها را بازیابی می‌نماید.

import { create } from 'zustand';
import { persist } from 'zustand/middleware';

const useAuthStore = create(
  persist(
    (set) => ({
      user: null,
      setUser: (user) => set({ user }),
      logout: () => set({ user: null }),
    }),
    {
      name: 'auth-storage', // کلید ذخیره در localStorage
      getStorage: () => localStorage, // به‌صورت پیش‌فرض همین است
    }
  )
);

export default useAuthStore;

اکنون، هر تغییری در user در localStorage ذخیره می‌شود، و هنگام بارگذاری مجدد صفحه، وضعیت قبلی بازیابی خواهد شد.

در پروژه‌های Next.js که دارای SSR هستند، باید دقت داشته باشید که localStorage فقط در سمت کلاینت در دسترس است.

getStorage: () => (typeof window !== 'undefined' ? localStorage : undefined)

اگر بخواهید به‌صورت دستی اطلاعات را از حافظه مرورگر پاک کنید از کد زیر استفاده کنید:

useAuthStore.persist.clearStorage(); // پاک‌سازی localStorage مربوط به Store

امیدواریم از این مقاله مدیریت state در ری اکت و آموزش zustand نهایت استفاده را برده باشید و آن را با دوستانتان به اشتراک بگذارید. تیم تولید محتوای مدرسه اینترنتی پرنیان این مقاله را تهیه کرده است.

اشتراک گذاری:
درباره مدیریت

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

نوشته های بیشتر از مدیریت
در تلگرام
کانال ما را دنبال کنید!
در اینستاگرام
ما را دنبال کنید!
در یوتوب
ما را دنبال کنید!
Created by potrace 1.14, written by Peter Selinger 2001-2017
در آپارات
ما را دنبال کنید!

مطالب زیر را حتما مطالعه کنید

Vibe Coding چیست؟ آیا آینده برنامه‌نویسی تغییر کرده است؟
Vibe Coding چیست؟ آیا آینده برنامه‌نویسی تغییر کرده است؟
MCP چیست
MCP چیست و چرا آینده برنامه‌نویسی با هوش مصنوعی را تغییر می‌دهد؟
تفاوت HTMLCollection و NodeList در جاوا اسکریپت
تفاوت HTMLCollection و NodeList در جاوا اسکریپت
State Normalization در فرانت‌اند چیست؟
State Normalization در فرانت‌اند چیست؟
حفظ روحیه برنامه نویسان در شرایط جنگی
حفظ روحیه برنامه نویسان در شرایط جنگی
خبر فوری
اطلاعیه مهم درباره شروع کلاس ها
قدیمی تر آموزش جامع و کامل نرم افزار Postman
جدیدتر پایان دوره شانزدهم پرنیان

3 دیدگاه

به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.

  • نیلوفر یوسفی گفت:
    31 مرداد 1403 در 6:31 ب.ظ

    مطالعه کردم-بسیار عاااااالی و به روز – تشکر استااااااد عزیز👌

    پاسخ
    • مدیریت گفت:
      1 شهریور 1403 در 9:10 ق.ظ

      سپاس از شما

      پاسخ
  • مهناز گفت:
    7 مرداد 1404 در 1:17 ب.ظ

    خیلی استفاده کردیم ممنون

    پاسخ

دیدگاهتان را بنویسید لغو پاسخ

جستجو برای:
نوشته‌های تازه
  • پایان دوره بابک
  • Vibe Coding چیست؟ آیا آینده برنامه‌نویسی تغییر کرده است؟
  • MCP چیست و چرا آینده برنامه‌نویسی با هوش مصنوعی را تغییر می‌دهد؟
  • تفاوت HTMLCollection و NodeList در جاوا اسکریپت
  • State Normalization در فرانت‌اند چیست؟
دسته‌ها
دوره ها:

کلاس های درحال ثبت نام فرانت اند: 

  • دوره فرانت اند صبح از اوایل آبان
  • دوره جاوا اسکریپت و ری اکت از 31مرداد

دوره فرانت اند پرنیان

 

مدرسه فرانت اند پرنیان

گروه آموزشی پرنیان از سال 92 تاسیس شده و تاکنون ده ها دوره طراحی وب ، CMS ، سئو و بوت کمپ فرانت اند به صورت حضوری و غیر حضوری برگزار کرده است. ما در پرنیان جدیدترین و کاربردی ترین مباحث طراحی و توسعه وب ، سئو و دیجیتال مارکتینگ رو آموزش داده و راه ورود شما عزیزان به بازار کار را هموار کرده ایم.

فهرست سفارشی
  • بلاگ
  • تماس با ما
  • حساب کاربری من
  • درباره پارسا قربانیان، موسس مدرسه پرنیان
  • سبد خرید
  • فروشگاه

لوگوی مدرسه پرنیان

تمام حقوق برای مدرسه فرانت اند پرنیان محفوظ است. سیاست حفظ حریم شخصی

ورود

رمز عبور را فراموش کرده اید؟

هنوز عضو نشده اید؟ عضویت در سایت