O'zbek

React'ning useReducer hook'i yordamida murakkab ilova holatlarini samarali boshqaring, global loyihalar unumdorligi va texnik xizmat ko'rsatish qulayligini oshiring.

React useReducer Pattern: Murakkab holatlarni boshqarishni o'zlashtirish

Doimiy rivojlanib borayotgan front-end dasturlash sohasida React foydalanuvchi interfeyslarini yaratish uchun yetakchi freymvork sifatida o'z o'rnini egalladi. Ilovalar murakkablashgan sari holatni boshqarish tobora qiyinlashib bormoqda. useState hook'i komponent ichidagi holatni boshqarishning oddiy usulini taqdim etadi, ammo murakkabroq stsenariylar uchun React kuchli alternativani taklif qiladi: useReducer hook'i. Ushbu blog posti useReducer patternini chuqur o'rganib, uning afzalliklari, amaliy qo'llanilishi va global miqyosda React ilovalaringizni qanday sezilarli darajada yaxshilashi mumkinligini ko'rib chiqadi.

Murakkab holatlarni boshqarish zaruratini tushunish

React ilovalarini yaratishda biz ko'pincha komponent holati shunchaki oddiy qiymat emas, balki o'zaro bog'liq ma'lumotlar to'plami yoki oldingi holat qiymatlariga bog'liq bo'lgan holatlarga duch kelamiz. Quyidagi misollarni ko'rib chiqing:

Bunday stsenariylarda faqat useState'dan foydalanish murakkab va boshqarish qiyin bo'lgan kodga olib kelishi mumkin. Bitta hodisaga javoban bir nechta holat o'zgaruvchilarini yangilash noqulay bo'lishi mumkin va bu yangilanishlarni boshqarish mantig'i komponent bo'ylab tarqalib ketishi uni tushunish va qo'llab-quvvatlashni qiyinlashtiradi. Aynan shu yerda useReducer o'zining afzalliklarini namoyon qiladi.

useReducer Hook'i bilan tanishuv

useReducer hook'i murakkab holat mantig'ini boshqarish uchun useState'ga alternativadir. U Redux patterni tamoyillariga asoslangan, lekin React komponentining o'zida amalga oshirilgan bo'lib, ko'p hollarda alohida tashqi kutubxonaga bo'lgan ehtiyojni yo'qotadi. U holatni yangilash mantig'ingizni reducer deb ataladigan yagona funksiyada markazlashtirishga imkon beradi.

useReducer hook'i ikkita argument qabul qiladi:

Hook ikkita elementdan iborat massivni qaytaradi:

Reducer Funksiyasi

Reducer funksiyasi useReducer patternining yuragi hisoblanadi. Bu sof funksiya bo'lib, u hech qanday qo'shimcha ta'sirga ega bo'lmasligi (masalan, API so'rovlarini amalga oshirish yoki global o'zgaruvchilarni o'zgartirish) va bir xil kirish ma'lumotlari uchun har doim bir xil natijani qaytarishi kerak. Reducer funksiyasi ikkita argument qabul qiladi:

Reducer funksiyasi ichida siz turli amal turlarini boshqarish va holatni mos ravishda yangilash uchun switch operatori yoki if/else if iboralaridan foydalanasiz. Bu holatni yangilash mantig'ingizni markazlashtiradi va turli hodisalarga javoban holat qanday o'zgarishini tushunishni osonlashtiradi.

Dispatch Funksiyasi

Dispatch funksiyasi holat yangilanishlarini ishga tushirish uchun ishlatiladigan usuldir. Siz dispatch(action)'ni chaqirganingizda, amal reducer funksiyasiga uzatiladi, so'ngra u amalning turi va payload'iga qarab holatni yangilaydi.

Amaliy Misol: Hisoblagichni Yaratish

Keling, oddiy misoldan boshlaylik: hisoblagich komponenti. Bu murakkabroq misollarga o'tishdan oldin asosiy tushunchalarni ko'rsatib beradi. Biz oshirish, kamaytirish va qayta o'rnatish mumkin bo'lgan hisoblagich yaratamiz:


import React, { useReducer } from 'react';

// Amal turlarini aniqlash
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
const RESET = 'RESET';

// Reducer funksiyasini aniqlash
function counterReducer(state, action) {
  switch (action.type) {
    case INCREMENT:
      return { count: state.count + 1 };
    case DECREMENT:
      return { count: state.count - 1 };
    case RESET:
      return { count: 0 };
    default:
      return state;
  }
}

function Counter() {
  // useReducer'ni ishga tushirish
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });

  return (
    <div>
      <p>Hisob: {state.count}</p>
      <button onClick={() => dispatch({ type: INCREMENT })}>Oshirish</button>
      <button onClick={() => dispatch({ type: DECREMENT })}>Kamaytirish</button>
      <button onClick={() => dispatch({ type: RESET })}>Qayta o'rnatish</button>
    </div>
  );
}

export default Counter;

Ushbu misolda:

Hisoblagich Misolini Kengaytirish: Payload Qo'shish

Keling, hisoblagichni ma'lum bir qiymatga oshirish imkoniyatini qo'shish uchun o'zgartiraylik. Bu amalga payload tushunchasini kiritadi:


import React, { useReducer } from 'react';

const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
const RESET = 'RESET';
const SET_VALUE = 'SET_VALUE';

function counterReducer(state, action) {
  switch (action.type) {
    case INCREMENT:
      return { count: state.count + action.payload };
    case DECREMENT:
      return { count: state.count - action.payload };
    case RESET:
      return { count: 0 };
    case SET_VALUE:
      return { count: action.payload };
    default:
      return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });
  const [inputValue, setInputValue] = React.useState(1);

  return (
    <div>
      <p>Hisob: {state.count}</p>
      <button onClick={() => dispatch({ type: INCREMENT, payload: parseInt(inputValue) || 1 })}>{inputValue} ga oshirish</button>
      <button onClick={() => dispatch({ type: DECREMENT, payload: parseInt(inputValue) || 1 })}>{inputValue} ga kamaytirish</button>
      <button onClick={() => dispatch({ type: RESET })}>Qayta o'rnatish</button>
       <input
         type="number"
         value={inputValue}
         onChange={(e) => setInputValue(e.target.value)}
       />
      </div>
  );
}

export default Counter;

Ushbu kengaytirilgan misolda:

useReducer'dan Foydalanishning Afzalliklari

useReducer patterni murakkab holatlarni boshqarish uchun useState'ni to'g'ridan-to'g'ri ishlatishga nisbatan bir nechta afzalliklarni taqdim etadi:

useReducer'ni qachon ishlatish kerak

useReducer muhim afzalliklarni taqdim etsa-da, u har doim ham to'g'ri tanlov emas. useReducer'ni ishlatishni ko'rib chiqing, qachonki:

Oddiy holat yangilanishlari uchun useState ko'pincha yetarli va ishlatish osonroq. Qaror qabul qilishda holatingizning murakkabligini va kelajakda kengayish ehtimolini hisobga oling.

Ilg'or Konsepsiyalar va Texnikalar

useReducer'ni Context bilan birgalikda ishlatish

Global holatni boshqarish yoki holatni bir nechta komponentlar o'rtasida bo'lishish uchun siz useReducer'ni React'ning Context API bilan birlashtirishingiz mumkin. Ushbu yondashuv ko'pincha qo'shimcha bog'liqliklarni kiritishni istamaydigan kichik va o'rta hajmdagi loyihalar uchun Redux'dan afzalroqdir.


import React, { createContext, useReducer, useContext } from 'react';

// Amal turlari va reducer'ni aniqlash (avvalgidek)
const INCREMENT = 'INCREMENT';
// ... (boshqa amal turlari va counterReducer funksiyasi)

const CounterContext = createContext();

function CounterProvider({ children }) {
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });

  return (
    <CounterContext.Provider value={{ state, dispatch }}>
      {children}
    </CounterContext.Provider>
  );
}

function useCounter() {
  return useContext(CounterContext);
}

function Counter() {
  const { state, dispatch } = useCounter();

  return (
    <div>
      <p>Hisob: {state.count}</p>
      <button onClick={() => dispatch({ type: INCREMENT })}>Oshirish</button>
    </div>
  );
}

function App() {
  return (
    <CounterProvider>
      <Counter />
    </CounterProvider>
  );
}

export default App;

Ushbu misolda:

useReducer'ni Testlash

Reducer'larni testlash oson, chunki ular sof funksiyalardir. Siz reducer funksiyasini Jest yoki Mocha kabi unit testlash freymvorklari yordamida alohida sinab ko'rishingiz mumkin. Quyida Jest yordamida misol keltirilgan:


import { counterReducer } from './counterReducer'; // counterReducer alohida faylda deb faraz qilamiz

const INCREMENT = 'INCREMENT';

describe('counterReducer', () => {
  it('hisobni oshirishi kerak', () => {
    const state = { count: 0 };
    const action = { type: INCREMENT };
    const newState = counterReducer(state, action);
    expect(newState.count).toBe(1);
  });

   it('noma`lum amal turlari uchun bir xil holatni qaytarishi kerak', () => {
        const state = { count: 10 };
        const action = { type: 'UNKNOWN_ACTION' };
        const newState = counterReducer(state, action);
        expect(newState).toBe(state); // Holat o'zgarmaganligini tasdiqlash
    });
});

Reducer'laringizni testlash ularning kutilganidek ishlashini ta'minlaydi va holat mantig'ingizni refaktoring qilishni osonlashtiradi. Bu mustahkam va qo'llab-quvvatlanadigan ilovalar yaratishda muhim qadamdir.

Memoizatsiya yordamida Samaradorlikni Optimallashtirish

Murakkab holatlar va tez-tez yangilanishlar bilan ishlaganda, komponentlaringiz samaradorligini optimallashtirish uchun useMemo'dan foydalanishni ko'rib chiqing, ayniqsa holatga asoslanib hisoblangan hosilaviy qiymatlaringiz bo'lsa. Masalan:


import React, { useReducer, useMemo } from 'react';

function reducer(state, action) {
  // ... (reducer mantig'i) 
}

function MyComponent() {
  const [state, dispatch] = useReducer(reducer, initialState);

  // Hosilaviy qiymatni hisoblash, uni useMemo bilan memoizatsiya qilish
  const derivedValue = useMemo(() => {
    // Holatga asoslangan qimmat hisoblash
    return state.value1 + state.value2;
  }, [state.value1, state.value2]); // Bog'liqliklar: faqat bu qiymatlar o'zgarganda qayta hisoblash

  return (
    <div>
      <p>Hosilaviy Qiymat: {derivedValue}</p>
      <button onClick={() => dispatch({ type: 'UPDATE_VALUE1', payload: 10 })}>1-Qiymatni Yangilash</button>
      <button onClick={() => dispatch({ type: 'UPDATE_VALUE2', payload: 20 })}>2-Qiymatni Yangilash</button>
    </div>
  );
}

Ushbu misolda, derivedValue faqat state.value1 yoki state.value2 o'zgarganda hisoblanadi, bu esa har bir qayta renderda keraksiz hisob-kitoblarning oldini oladi. Bu yondashuv optimal render samaradorligini ta'minlash uchun keng tarqalgan amaliyotdir.

Haqiqiy Dunyo Misollari va Qo'llash Holatlari

Keling, global auditoriya uchun React ilovalarini yaratishda useReducer qimmatli vosita bo'lgan bir nechta amaliy misollarni ko'rib chiqaylik. E'tibor bering, bu misollar asosiy tushunchalarni ko'rsatish uchun soddalashtirilgan. Haqiqiy ilovalarda murakkabroq mantiq va bog'liqliklar bo'lishi mumkin.

1. Elektron tijorat mahsulot filtrlari

Katta mahsulot katalogiga ega bo'lgan elektron tijorat veb-saytini (global miqyosda mavjud bo'lgan Amazon yoki AliExpress kabi mashhur platformalarni o'ylang) tasavvur qiling. Foydalanuvchilar mahsulotlarni turli mezonlar (narx oralig'i, brend, o'lcham, rang, ishlab chiqarilgan mamlakat va boshqalar) bo'yicha filtrlashi kerak. useReducer filtr holatini boshqarish uchun idealdir.


import React, { useReducer } from 'react';

const initialState = {
  priceRange: { min: 0, max: 1000 },
  brand: [], // Tanlangan brendlar massivi
  color: [], // Tanlangan ranglar massivi
  //... boshqa filtr mezonlari
};

function filterReducer(state, action) {
  switch (action.type) {
    case 'UPDATE_PRICE_RANGE':
      return { ...state, priceRange: action.payload };
    case 'TOGGLE_BRAND':
      const brand = action.payload;
      return { ...state, brand: state.brand.includes(brand) ? state.brand.filter(b => b !== brand) : [...state.brand, brand] };
    case 'TOGGLE_COLOR':
      // Rang filtrlash uchun o'xshash mantiq
      return { ...state, color: state.color.includes(action.payload) ? state.color.filter(c => c !== action.payload) : [...state.color, action.payload] };
    // ... boshqa filtr amallari
    default:
      return state;
  }
}

function ProductFilter() {
  const [state, dispatch] = useReducer(filterReducer, initialState);

  // Filtr mezonlarini tanlash va dispatch amallarini ishga tushirish uchun UI komponentlari
  // Masalan: Narx uchun diapazon kiritish, brendlar uchun checkbox'lar va h.k.

  return (
    <div>
      <!-- Filtr UI elementlari -->
    </div>
  );
}

Ushbu misol bir nechta filtr mezonlarini boshqariladigan tarzda qanday ishlashni ko'rsatadi. Foydalanuvchi har qanday filtr sozlamasini (narx, brend va h.k.) o'zgartirganda, reducer filtr holatini mos ravishda yangilaydi. Keyin mahsulotlarni ko'rsatish uchun mas'ul bo'lgan komponent yangilangan holatdan foydalanib ko'rsatiladigan mahsulotlarni filtrlaydi. Ushbu pattern global elektron tijorat platformalarida keng tarqalgan murakkab filtrlash tizimlarini yaratishni qo'llab-quvvatlaydi.

2. Ko'p bosqichli formalar (masalan, xalqaro yetkazib berish formalari)

Ko'pgina ilovalar xalqaro yetkazib berish yoki murakkab talablarga ega foydalanuvchi hisoblarini yaratish uchun ishlatiladigan kabi ko'p bosqichli formalarni o'z ichiga oladi. useReducer bunday formalarning holatini boshqarishda a'lo darajada ishlaydi.


import React, { useReducer } from 'react';

const initialState = {
  step: 1, // Formadagi joriy bosqich
  formData: {
    firstName: '',
    lastName: '',
    address: '',
    city: '',
    country: '',
    // ... boshqa forma maydonlari
  },
  errors: {},
};

function formReducer(state, action) {
  switch (action.type) {
    case 'NEXT_STEP':
      return { ...state, step: state.step + 1 };
    case 'PREV_STEP':
      return { ...state, step: state.step - 1 };
    case 'UPDATE_FIELD':
      return { ...state, formData: { ...state.formData, [action.payload.field]: action.payload.value } };
    case 'SET_ERRORS':
      return { ...state, errors: action.payload };
    case 'SUBMIT_FORM':
      // Forma yuborish mantig'ini bu yerda bajaring, masalan, API so'rovlari
      return state;
    default:
      return state;
  }
}

function MultiStepForm() {
  const [state, dispatch] = useReducer(formReducer, initialState);

  // Formaning har bir bosqichi uchun render qilish mantig'i
  // Holatdagi joriy bosqichga asoslangan
  const renderStep = () => {
    switch (state.step) {
      case 1:
        return <Step1 formData={state.formData} dispatch={dispatch} />;
      case 2:
        return <Step2 formData={state.formData} dispatch={dispatch} />;
      // ... boshqa bosqichlar
      default:
        return <p>Noto'g'ri bosqich</p>;
    }
  };

  return (
    <div>
      {renderStep()}
      <!-- Joriy bosqichga asoslangan navigatsiya tugmalari (Keyingi, Oldingi, Yuborish) -->
    </div>
  );
}

Bu turli forma maydonlari, bosqichlar va ehtimoliy validatsiya xatolarini tuzilgan va qo'llab-quvvatlanadigan tarzda qanday boshqarishni ko'rsatadi. Bu, ayniqsa, Facebook yoki WeChat kabi turli platformalardagi mahalliy urf-odatlar va tajribalariga asoslanib turli xil kutishlarga ega bo'lishi mumkin bo'lgan xalqaro foydalanuvchilar uchun foydalanuvchilarga qulay ro'yxatdan o'tish yoki buyurtma berish jarayonlarini yaratish uchun juda muhimdir.

3. Real vaqtda ishlaydigan ilovalar (chat, hamkorlik vositalari)

useReducer real vaqtda ishlaydigan ilovalar, masalan, Google Docs kabi hamkorlik vositalari yoki xabar almashish ilovalari uchun foydalidir. U xabarlarni qabul qilish, foydalanuvchining qo'shilishi/chiqishi va ulanish holati kabi hodisalarni boshqarib, UI kerakli darajada yangilanishini ta'minlaydi.


import React, { useReducer, useEffect } from 'react';

const initialState = {
  messages: [],
  users: [],
  connectionStatus: 'connecting',
};

function chatReducer(state, action) {
  switch (action.type) {
    case 'RECEIVE_MESSAGE':
      return { ...state, messages: [...state.messages, action.payload] };
    case 'USER_JOINED':
      return { ...state, users: [...state.users, action.payload] };
    case 'USER_LEFT':
      return { ...state, users: state.users.filter(user => user.id !== action.payload.id) };
    case 'SET_CONNECTION_STATUS':
      return { ...state, connectionStatus: action.payload };
    default:
      return state;
  }
}

function ChatRoom() {
  const [state, dispatch] = useReducer(chatReducer, initialState);

  useEffect(() => {
    // WebSocket ulanishini o'rnatish (misol):
    const socket = new WebSocket('wss://your-websocket-server.com');

    socket.onopen = () => dispatch({ type: 'SET_CONNECTION_STATUS', payload: 'connected' });
    socket.onmessage = (event) => dispatch({ type: 'RECEIVE_MESSAGE', payload: JSON.parse(event.data) });
    socket.onclose = () => dispatch({ type: 'SET_CONNECTION_STATUS', payload: 'disconnected' });

    return () => socket.close(); // Komponent o'chirilganda tozalash
  }, []);

  // Holatga asoslanib xabarlar, foydalanuvchilar ro'yxati va ulanish holatini render qilish
  return (
    <div>
      <p>Ulanish holati: {state.connectionStatus}</p>
      <!-- Xabarlarni ko'rsatish, foydalanuvchilar ro'yxati va xabar yuborish uchun UI -->
    </div>
  );
}

Ushbu misol real vaqtda ishlaydigan chatni boshqarish uchun asos yaratadi. Holat xabarlarni saqlash, hozirda chatda bo'lgan foydalanuvchilar va ulanish holatini boshqaradi. useEffect hook'i WebSocket ulanishini o'rnatish va kiruvchi xabarlarni boshqarish uchun mas'uldir. Bu yondashuv butun dunyo bo'ylab foydalanuvchilarga xizmat ko'rsatadigan sezgir va dinamik foydalanuvchi interfeysini yaratadi.

useReducer'dan foydalanish bo'yicha eng yaxshi amaliyotlar

useReducer'dan samarali foydalanish va qo'llab-quvvatlanadigan ilovalar yaratish uchun quyidagi eng yaxshi amaliyotlarni ko'rib chiqing:

Xulosa

useReducer hook'i React ilovalarida murakkab holatni boshqarish uchun kuchli va ko'p qirrali vositadir. U markazlashtirilgan holat mantig'i, yaxshilangan kod tashkiloti va kuchaytirilgan testlanuvchanlik kabi ko'plab afzalliklarni taqdim etadi. Eng yaxshi amaliyotlarga rioya qilish va uning asosiy tushunchalarini tushunish orqali siz yanada mustahkam, qo'llab-quvvatlanadigan va samarali React ilovalarini yaratish uchun useReducer'dan foydalanishingiz mumkin. Ushbu pattern murakkab holatlarni boshqarish muammolarini samarali hal qilish imkonini beradi, bu esa butun dunyo bo'ylab uzluksiz foydalanuvchi tajribasini taqdim etadigan global miqyosdagi ilovalarni yaratishga imkon beradi.

React dasturlashiga chuqurroq kirib borganingiz sari, useReducer patternini o'z vositalaringiz to'plamiga kiritish, shubhasiz, toza, kengaytiriladigan va oson qo'llab-quvvatlanadigan kod bazalariga olib keladi. Har doim ilovangizning o'ziga xos ehtiyojlarini hisobga olishni va har bir vaziyat uchun holatni boshqarishning eng yaxshi yondashuvini tanlashni unutmang. Dasturlashingiz muvaffaqiyatli bo'lsin!