React Azerbaycan Dilinde İzahli useReducer Hook

React Azerbaycan Dilinde İzahli useReducer Hook

React useReducer Hook-u: Azərbaycan dilində tam izah və istifadə nümunələri

React-də useReducer Hook-u, daha mürəkkəb komponent vəziyyətlərini idarə etmək üçün geniş istifadə olunur. Bu yazıda, useReducer-in nə olduğu, necə işlədiyi və hansı hallarda istifadə edilməli olduğu Azərbaycan dilində sadə və aydın şəkildə izah olunur. Yazının sonunda isə frontend müsahibələrində qarşınıza çıxa biləcək suallara cavabları da təqdim edirik. 

Note: Bir öncəki bloqda useRef Hook Azərbaycan dilində izahı paylaşılıb, əgər oxumamısınızsa linkə daxil olaraq məlumat ala bilərsiniz.

useReducer React Hook-dur və komponentinizə reducer əlavə etməyə imkan verir.

useReducer(reducer, initialArg, init?)
Komponentinizin yuxarı səviyyəsində useReducer-u çağıraraq onun state-nə reducer ilə nəzarət edin.

import { useReducer } from 'react';

function reducer(state, action) {
 // ...
}

function MyComponent() {
 const [state, dispatch] = useReducer(reducer, { age: 42 });
 // ...
}

 

useReducer Parametrlər

  • reducer: State-in necə yenilənəcəyini göstərən reducer funksiyasıdır. O, saf olmalıdır, state və action arqumentləri qəbul etməlidir və növbəti state-i qaytarmalıdır. State və action istənilən tipdə ola bilər.
  • initialArg: Başlanğıc state-in hesablandığı dəyərdir. İstənilən tipdə ola bilər. Başlanğıc state-in necə hesablanması init arqumentindən asılıdır.
  • optional init: Başlanğıc state-i qaytarmalı olan başlatma funksiyasıdır. Əgər göstərilməyibsə, başlanğıc state initialArg olur. Əks halda, başlanğıc state init(initialArg) çağırışının nəticəsi olur.

useReducer Returns

useReducer tam olaraq iki dəyərdən ibarət array qaytarır:

  • current state. İlk render zamanı bu init(initialArg) və ya initialArg olur (əgər init yoxdursa).
  • State-i başqa dəyərə yeniləməyə və renderin yenidən başlamasına imkan verən dispatch funksiyası.

useReduser İstifadəsi Zamanı Önəmli Qeydlər

useReducer harada istifadə oluna bilər?

React qaydalarına görə (Rules of Hooks):

useReducer, useState Hook-ları yalnız komponentin yuxarı səviyyəsində çağırıla bilər. Yəni dövrlərin (for, while) və ya şərtlərin (if) içində çağırmaq olmaz.

//Doğru:

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

 

//Yanlış

function MyComponent() {
 if (something) {
   const [state, dispatch] = useReducer(reducer, initialState); // YANLIŞ
 }
}

 

dispatch funksiyası sabitdir (stable identity)

Bu o deməkdir ki:

dispatch dəyişməz funksiyadır. Komponent təkrar render olsa da, dispatch funksiyası dəyişmir. Ona görə də onu useEffect asılılığına əlavə etməyə ehtiyac yoxdur.

useEffect(() => {
 // dispatch burda dəyişmədiyi üçün linter onu asılılığa əlavə etməyə məcbur etmir
 dispatch({ type: 'DO_SOMETHING' });
}, []); // dispatch əlavə etməyə ehtiyac yoxdur

 

Strict Mode və useReducer

Frontend Proqramlaşdırmada React-ın Strict Mode rejimi (ən çox development mühitində aktiv olur), komponentin içindəki bəzi funksiyaları iki dəfə çağırır.

Bu məqsəd:

  • Təmiz olmayan (impure) funksiyaları tapmaq.
  • Yan təsirləri müəyyənləşdirmək.

Bu rejimdə:

  • reducer funksiyan sınaq üçün iki dəfə çağırıla bilər.
  • Amma yalnız birinci çağırışın nəticəsi istifadə olunur. İkincisi sadəcə test məqsədi daşıyır.

Əgər sənin reducer funksiyan safdırsa (pure function – yəni eyni state və action verildikdə həmişə eyni nəticəni verir və heç bir yan təsiri yoxdur), bu iki dəfə çağırılma heç bir problem yaratmamalıdır.

function reducer(state, action) {
 // bu funksiya saf olmalıdır
 switch (action.type) {
   case "increment":
     return { count: state.count + 1 };
   default:
     return state;
 }
}

 

dispatch funksiyası

useReducer tərəfindən qaytarılan dispatch funksiyası state-i başqa bir dəyərə yeniləməyə və yenidən renderi tetikleməyə imkan verir. dispatch funksiyasına yalnız bir arqument olaraq action-ı ötürməyiniz lazımdır:

const [state, dispatch] = useReducer(reducer, { age: 42 });

function handleClick() {
 dispatch({ type: 'incremented_age' });
 // ...
}

 

React, növbəti state-i sizin təqdim etdiyiniz reducer funksiyasını cari statedispatch-ə ötürdüyünüz action ilə çağıraraq hesablayacaq.

action: İstifadəçi tərəfindən həyata keçirilən hərəkətdir. Bu, istənilən tipdə dəyər ola bilər. Ənənəvi olaraq, action adətən onu tanıdan type xüsusiyyətinə və əlavə məlumatlar üçün digər xüsusiyyətlərə malik obyekt olur.

dispatch funksiyaları heç bir nəticə qaytarmır.

Xatırlatmalar

dispatch funksiyası yalnız növbəti render üçün state dəyişəni yeniləyir. Əgər dispatch funksiyasını çağırdıqdan sonra state dəyişənini oxuyarsınızsa, hələ də əvvəlki, ekranda olan köhnə dəyəri görəcəksiniz.

Əgər verdiyiniz yeni dəyər Object.is müqayisəsinə əsasən cari state ilə eynidirsə, React komponenti və onun uşaqlarını yenidən render etməyəcək. Bu, performans üçün edilən optimizasiyadır. React komponentinizi çağırmalı olsa da, nəticəni nəzərə almaya bilər, lakin bu kodunuza təsir etməməlidir.

React state yeniləmələrini toplu şəkildə həyata keçirir. Ekranı yalnız bütün event handler-lər işini bitirdikdən və öz set funksiyalarını çağırdıqdan sonra yeniləyir. Bu, bir hadisə zamanı bir neçə dəfə render etməyin qarşısını alır. Nadir hallarda, məsələn DOM-a dərhal çıxış lazım olduqda, React-ı daha tez ekranı yeniləməyə məcbur etmək üçün flushSync istifadə edə bilərsiniz.

React useReducer İstifadə qaydası

Komponentə reducer əlavə etmək

useReducer-i komponentinizin ən üst səviyyəsində çağıraraq state-i reducer ilə idarə edin.

import { useReducer } from 'react';

function reducer(state, action) {
 // ...
}

function MyComponent() {
 const [state, dispatch] = useReducer(reducer, { age: 42 });
 // ...
}

 

useReducer tam olaraq iki elementdən ibarət bir massiv qaytarır:

  • Bu state dəyişəninin cari vəziyyəti, əvvəlcə sizin verdiyiniz ilkin vəziyyətə (initial state) qurulur.
  • dispatch funksiyası, qarşılıqlı təsirə cavab olaraq bu vəziyyəti dəyişməyə imkan verir.

Ekranda göstərilənləri yeniləmək üçün istifadəçinin etdiyi hərəkəti təmsil edən bir obyektlə dispatch çağırın; bu obyekt action adlanır:

function handleClick() {
 dispatch({ type: 'incremented_age' });
}

 

React sizin reducer funksiyanıza cari stateaction-ı ötürəcək. Sizin reducer funksiyanız növbəti vəziyyəti hesablayacaq və qaytaracaq. React həmin növbəti state-i yadda saxlayacaq, komponentinizi bununla birlikdə yenidən render edəcək və UI-i yeniləyəcək.

import { useReducer } from 'react';

function reducer(state, action) {
 if (action.type === 'incremented_age') {
   return {
     age: state.age + 1
   };
 }
 throw Error('Unknown action.');
}

export default function Counter() {
 const [state, dispatch] = useReducer(reducer, { age: 42 });

 return (
   <>
     <button onClick={() => {
       dispatch({ type: 'incremented_age' })
     }}>
       Increment age
     </button>
     <p>Hello! You are {state.age}.</p>
   </>
 );
}

 

useReducer, useState-ə çox bənzəyir, lakin vəziyyətin yenilənməsi məntiqini event handler-lardan komponentdən kənardakı tək bir funksiyaya köçürməyə imkan verir. useState ilə useReducer arasında seçim barədə daha ətraflı oxuyun.

Reducer funksiyasının yazılması

Reducer funksiyası aşağıdakı kimi yazılır:

function reducer(state, action) {
 // ...
}

 

Daha sonra isə növbəti state-i hesablayıb qaytaran kodu doldurmaq lazımdır. Adətən, bu funksiyanı switch ifadəsi kimi yazmaq geniş yayılmışdır. switch-in hər bir halı (case) üçün növbəti state-i hesablayın və qaytarın:

function reducer(state, action) {
 switch (action.type) {
   case 'incremented_age': {
     return {
       name: state.name,
       age: state.age + 1
     };
   }
   case 'changed_name': {
     return {
       name: action.nextName,
       age: state.age
     };
   }
 }
 throw Error('Unknown action: ' + action.type);
}

 

Action-lar istənilən quruluşda ola bilər. Adətən, içərisində type adlı sahə olan obyekt ötürülür ki, bu da action-ı müəyyən edir. O, reducer-in növbəti vəziyyəti hesablaması üçün lazım olan minimum məlumatı ehtiva etməlidir.

function Form() {
 const [state, dispatch] = useReducer(reducer, { name: 'Taylor', age: 42 });
 
 function handleButtonClick() {
   dispatch({ type: 'incremented_age' });
 }

 function handleInputChange(e) {
   dispatch({
     type: 'changed_name',
     nextName: e.target.value
   });
 }
 // ...
}

 

Action tiplərinin adları sizin komponentinizə aiddir (lokaldır). Hər bir action tək bir qarşılıqlı təsviri ifadə edir, baxmayaraq ki, bu bir neçə məlumat dəyişməsinə səbəb ola bilər. State-in quruluşu istənilən formada ola bilər, lakin adətən bu, obyekt və ya massiv olur.

Əlavə məlumat üçün “state məntiqini reducer funksiyasına çıxarmaq” mövzusunu oxuyun.

useReducer - Səhv yanaşma

State oxumaq üçün nəzərdə tutulub. Heç bir obyekt və ya massiv üzərində birbaşa dəyişiklik etməyin:

function reducer(state, action) {
 switch (action.type) {
   case 'incremented_age': {
     // 🚩 Bu şəkildə *state* obyektini dəyişmək olmaz:
     state.age = state.age + 1;
     return state;
   }
 }
}

 

useReducer - Düzgün yanaşma

Bunun əvəzinə reducer funksiyanızdan həmişə yeni obyekt qaytarın:

function reducer(state, action) {
 switch (action.type) {
   case 'incremented_age': {
     // ✅ Yeni obyekt qaytarmaqla düzgün yazılmış nümunə
     return {
       ...state,
       age: state.age + 1
     };
   }
 }
}

 

Əlavə məlumat üçün “state daxilində obyektlərin yenilənməsi” və “state daxilində massivlərin yenilənməsi” mövzularını oxuyun.

Nümunə - ToDo List

Aşağıda təqdim olunan Todo list nümunəsi useReducer ilə massivdə (array) tapşırıqların idarə olunmasını göstərir. Burada tapşırıq əlavə etmək, dəyişdirmək və silmək funksiyaları reducer vasitəsilə həyata keçirilir. Əsas məqsəd, mövcud massivi dəyişmədən (mutasiya etmədən) yenilənmiş yeni bir massiv qaytarmaqdır.

import { useReducer } from 'react';
import AddTask from './AddTask.js';
import TaskList from './TaskList.js';

function tasksReducer(tasks, action) {
 switch (action.type) {
   case 'added': {
     return [...tasks, {
       id: action.id,
       text: action.text,
       done: false
     }];
   }
   case 'changed': {
     return tasks.map(t => {
       if (t.id === action.task.id) {
         return action.task;
       } else {
         return t;
       }
     });
   }
   case 'deleted': {
     return tasks.filter(t => t.id !== action.id);
   }
   default: {
     throw Error('Unknown action: ' + action.type);
   }
 }
}

export default function TaskApp() {
 const [tasks, dispatch] = useReducer(
   tasksReducer,
   initialTasks
 );

 function handleAddTask(text) {
   dispatch({
     type: 'added',
     id: nextId++,
     text: text,
   });
 }

 function handleChangeTask(task) {
   dispatch({
     type: 'changed',
     task: task
   });
 }

 function handleDeleteTask(taskId) {
   dispatch({
     type: 'deleted',
     id: taskId
   });
 }

 return (
   <>
     <h1>Prague itinerary</h1>
     <AddTask
       onAddTask={handleAddTask}
     />
     <TaskList
       tasks={tasks}
       onChangeTask={handleChangeTask}
       onDeleteTask={handleDeleteTask}
     />
   </>
 );
}

let nextId = 3;
const initialTasks = [
 { id: 0, text: 'Visit Kafka Museum', done: true },
 { id: 1, text: 'Watch a puppet show', done: false },
 { id: 2, text: 'Lennon Wall pic', done: false }
];

 

  • useReducer, kompleks state dəyişikliklərini daha strukturlaşdırılmış şəkildə idarə etməyə kömək edir.
  • Hər bir dispatch çağırışı action obyektini reducer funksiyasına göndərir.
  • Heç vaxt mövcud state-i birbaşa dəyişməyin; hər zaman yeni obyekt və ya massiv qaytarın.
  • reducer-dəki hər case konkret bir əməliyyatı təmsil edir (added, changed, deleted).

useReducer - Nəticə

React-də useReducer Hook-u mürəkkəb komponent vəziyyətlərinin idarəsində güclü və effektiv vasitədir. Bu Hook, state məntiqini komponentdən ayıraraq daha təmiz, oxunaqlı və genişlənə bilən kod yazmağa imkan verir. Əgər siz özünüzün pulsuz sayt yaratmaq təcrübənizi inkişaf etdirmək istəyirsinizsə, useReducer-un düzgün istifadəsi frontend proqramlaşdırma bacarıqlarınızı artıracaq. Xüsusilə böyük və kompleks layihələrdə useReducer, useState-dən daha əlverişli və təmiz həll təqdim edir. Bu yazı ilə React-də useReducer-un əsaslarını öyrənərək, öz pulsuz və sayt yaratmaq layihələrinizdə tətbiq edə bilərsiniz.

Frontend Müsahibə Sualları

useState ilə useReducer arasındakı əsas fərq nədir?

useState sadə vəziyyət dəyişiklikləri üçün uyğundur, lakin useReducer bir neçə vəziyyətin və ya mürəkkəb dəyişikliklərin idarə olunması üçün daha əlverişlidir. useReducer-də dəyişikliklər reducer funksiyası ilə idarə olunur, bu isə kodun daha nizamlı olmasına kömək edir.

useReducer hansı hallarda daha üstün olur?

  • Kompleks vəziyyət dəyişiklikləri varsa
  • Birdən çox vəziyyət bir-biri ilə əlaqəlidirsə
  • Vəziyyət dəyişikliklərini mərkəzləşdirmək istəyirsinizsə
  • Kodun daha asan test oluna bilməsini istəyirsinizsə

useReducer-də dispatch funksiyasının sabit olması nə deməkdir?

Bu o deməkdir ki, dispatch funksiyasının referansı (identity) dəyişmir. Beləliklə, onu useEffect asılılığına əlavə etmək lazım deyil. Bu, performans baxımından da faydalıdır.