Lietuvių

Išsamiai išnagrinėkite React useReducer hook'ą, kad efektyviai valdytumėte sudėtingas programų būsenas, pagerintumėte našumą ir palaikomumą globaliuose React projektuose.

React useReducer šablonas: sudėtingos būsenos valdymo įsisavinimas

Nuolat kintančioje front-end kūrimo aplinkoje React įsitvirtino kaip pagrindinė vartotojo sąsajų kūrimo sistema. Programoms tampant sudėtingesnėms, būsenos valdymas tampa vis didesniu iššūkiu. useState hook'as suteikia paprastą būdą valdyti būseną komponente, tačiau sudėtingesniems scenarijams React siūlo galingą alternatyvą: useReducer hook'ą. Šiame tinklaraščio įraše gilinamasi į useReducer šabloną, nagrinėjami jo privalumai, praktiniai įgyvendinimai ir kaip jis gali ženkliai pagerinti jūsų React programas globaliu mastu.

Sudėtingos būsenos valdymo poreikio supratimas

Kuriant React programas, dažnai susiduriame su situacijomis, kai komponento būsena yra ne tik paprasta reikšmė, bet ir susijusių duomenų taškų rinkinys arba būsena, priklausanti nuo ankstesnių būsenos reikšmių. Apsvarstykite šiuos pavyzdžius:

Šiais atvejais, naudojant tik useState, kodas gali tapti sudėtingas ir sunkiai valdomas. Gali būti sudėtinga atnaujinti kelis būsenos kintamuosius reaguojant į vieną įvykį, o šių atnaujinimų valdymo logika gali išsibarstyti po visą komponentą, todėl jį sunku suprasti ir prižiūrėti. Būtent čia ir atsiskleidžia useReducer.

Pristatome useReducer Hook'ą

useReducer hook'as yra alternatyva useState, skirta sudėtingai būsenos logikai valdyti. Jis pagrįstas Redux šablono principais, tačiau įgyvendintas pačiame React komponente, todėl daugeliu atvejų nebereikia atskiros išorinės bibliotekos. Jis leidžia centralizuoti būsenos atnaujinimo logiką vienoje funkcijoje, vadinamoje reducer'iu.

useReducer hook'as priima du argumentus:

Hook'as grąžina masyvą, kuriame yra du elementai:

Reducer funkcija

Reducer funkcija yra useReducer šablono pagrindas. Tai grynoji funkcija, o tai reiškia, kad ji neturėtų turėti jokių šalutinių poveikių (pvz., daryti API užklausų ar keisti globalių kintamųjų) ir visada turėtų grąžinti tą patį rezultatą tiems patiems įvesties duomenims. Reducer funkcija priima du argumentus:

Reducer funkcijos viduje naudojate switch teiginį arba if/else if teiginius, kad apdorotumėte skirtingus veiksmų tipus ir atitinkamai atnaujintumėte būseną. Tai centralizuoja jūsų būsenos atnaujinimo logiką ir leidžia lengviau suprasti, kaip būsena keičiasi reaguojant į skirtingus įvykius.

Dispatch funkcija

Dispatch funkcija yra metodas, kurį naudojate būsenos atnaujinimams inicijuoti. Kai iškviečiate dispatch(action), veiksmas perduodamas reducer funkcijai, kuri atnaujina būseną pagal veiksmo tipą ir payload'ą.

Praktinis pavyzdys: skaitiklio įgyvendinimas

Pradėkime nuo paprasto pavyzdžio: skaitiklio komponento. Tai iliustruoja pagrindines sąvokas prieš pereinant prie sudėtingesnių pavyzdžių. Sukursime skaitiklį, kurį galima didinti, mažinti ir atstatyti:


import React, { useReducer } from 'react';

// Apibrėžiame veiksmų tipus
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
const RESET = 'RESET';

// Apibrėžiame reducer funkciją
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() {
  // Inicijuojame useReducer
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });

  return (
    <div>
      <p>Skaičius: {state.count}</p>
      <button onClick={() => dispatch({ type: INCREMENT })}>Didinti</button>
      <button onClick={() => dispatch({ type: DECREMENT })}>Mažinti</button>
      <button onClick={() => dispatch({ type: RESET })}>Atstatyti</button>
    </div>
  );
}

export default Counter;

Šiame pavyzdyje:

Skaitiklio pavyzdžio išplėtimas: Payload pridėjimas

Pakeiskime skaitiklį, kad būtų galima jį padidinti nurodyta reikšme. Tai supažindina su payload sąvoka veiksme:


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>Skaičius: {state.count}</p>
      <button onClick={() => dispatch({ type: INCREMENT, payload: parseInt(inputValue) || 1 })}>Didinti per {inputValue}</button>
      <button onClick={() => dispatch({ type: DECREMENT, payload: parseInt(inputValue) || 1 })}>Mažinti per {inputValue}</button>
      <button onClick={() => dispatch({ type: RESET })}>Atstatyti</button>
       <input
         type="number"
         value={inputValue}
         onChange={(e) => setInputValue(e.target.value)}
       />
      </div>
  );
}

export default Counter;

Šiame išplėstame pavyzdyje:

useReducer naudojimo privalumai

useReducer šablonas siūlo keletą privalumų, palyginti su tiesioginiu useState naudojimu sudėtingam būsenos valdymui:

Kada naudoti useReducer

Nors useReducer siūlo didelius privalumus, tai ne visada yra teisingas pasirinkimas. Apsvarstykite galimybę naudoti useReducer, kai:

Paprastiems būsenos atnaujinimams dažnai pakanka useState ir jį naudoti yra paprasčiau. Priimdami sprendimą, atsižvelkite į savo būsenos sudėtingumą ir galimą augimą.

Pažangios koncepcijos ir technikos

useReducer derinimas su Context

Norėdami valdyti globalią būseną arba dalytis būsena tarp kelių komponentų, galite derinti useReducer su React Context API. Šis metodas dažnai yra pageidautinesnis už Redux mažesniuose ir vidutinio dydžio projektuose, kur nenorite įtraukti papildomų priklausomybių.


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

// Apibrėžiame veiksmų tipus ir reducer'į (kaip anksčiau)
const INCREMENT = 'INCREMENT';
// ... (kiti veiksmų tipai ir counterReducer funkcija)

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>Skaičius: {state.count}</p>
      <button onClick={() => dispatch({ type: INCREMENT })}>Didinti</button>
    </div>
  );
}

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

export default App;

Šiame pavyzdyje:

useReducer testavimas

Reducer'ių testavimas yra paprastas, nes tai yra grynosios funkcijos. Galite lengvai testuoti reducer funkciją atskirai, naudodami vienetų testavimo sistemą, pavyzdžiui, Jest ar Mocha. Štai pavyzdys naudojant Jest:


import { counterReducer } from './counterReducer'; // Darant prielaidą, kad counterReducer yra atskirame faile

const INCREMENT = 'INCREMENT';

describe('counterReducer', () => {
  it('turėtų padidinti skaičių', () => {
    const state = { count: 0 };
    const action = { type: INCREMENT };
    const newState = counterReducer(state, action);
    expect(newState.count).toBe(1);
  });

   it('turėtų grąžinti tą pačią būseną nežinomiems veiksmų tipams', () => {
        const state = { count: 10 };
        const action = { type: 'UNKNOWN_ACTION' };
        const newState = counterReducer(state, action);
        expect(newState).toBe(state); // Patikriname, kad būsena nepasikeitė
    });
});

Reducer'ių testavimas užtikrina, kad jie veikia kaip tikėtasi, ir palengvina būsenos logikos pertvarkymą. Tai yra esminis žingsnis kuriant patikimas ir palaikomas programas.

Našumo optimizavimas su memoizacija

Dirbant su sudėtingomis būsenomis ir dažnais atnaujinimais, apsvarstykite galimybę naudoti useMemo, kad optimizuotumėte savo komponentų našumą, ypač jei turite išvestinių reikšmių, apskaičiuotų pagal būseną. Pavyzdžiui:


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

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

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

  // Apskaičiuojame išvestinę reikšmę, ją memoizuodami su useMemo
  const derivedValue = useMemo(() => {
    // Brangus skaičiavimas, pagrįstas būsena
    return state.value1 + state.value2;
  }, [state.value1, state.value2]); // Priklausomybės: perskaičiuoti tik pasikeitus šioms reikšmėms

  return (
    <div>
      <p>Išvestinė reikšmė: {derivedValue}</p>
      <button onClick={() => dispatch({ type: 'UPDATE_VALUE1', payload: 10 })}>Atnaujinti Value 1</button>
      <button onClick={() => dispatch({ type: 'UPDATE_VALUE2', payload: 20 })}>Atnaujinti Value 2</button>
    </div>
  );
}

Šiame pavyzdyje derivedValue apskaičiuojama tik tada, kai pasikeičia state.value1 arba state.value2, taip išvengiant nereikalingų skaičiavimų kiekvieno perpiešimo metu. Šis metodas yra įprasta praktika siekiant užtikrinti optimalų atvaizdavimo našumą.

Realaus pasaulio pavyzdžiai ir naudojimo atvejai

Panagrinėkime keletą praktinių pavyzdžių, kur useReducer yra vertingas įrankis kuriant React programas pasaulinei auditorijai. Atkreipkite dėmesį, kad šie pavyzdžiai yra supaprastinti, siekiant iliustruoti pagrindines sąvokas. Tikri įgyvendinimai gali apimti sudėtingesnę logiką ir priklausomybes.

1. El. prekybos produktų filtrai

Įsivaizduokite el. prekybos svetainę (pagalvokite apie populiarias platformas, tokias kaip Amazon ar AliExpress, prieinamas visame pasaulyje) su dideliu produktų katalogu. Vartotojams reikia filtruoti produktus pagal įvairius kriterijus (kainų intervalą, prekės ženklą, dydį, spalvą, kilmės šalį ir kt.). useReducer idealiai tinka filtrų būsenai valdyti.


import React, { useReducer } from 'react';

const initialState = {
  priceRange: { min: 0, max: 1000 },
  brand: [], // Pasirinktų prekės ženklų masyvas
  color: [], // Pasirinktų spalvų masyvas
  //... kiti filtravimo kriterijai
};

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':
      // Panaši logika spalvų filtravimui
      return { ...state, color: state.color.includes(action.payload) ? state.color.filter(c => c !== action.payload) : [...state.color, action.payload] };
    // ... kiti filtrų veiksmai
    default:
      return state;
  }
}

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

  // UI komponentai filtrų kriterijams pasirinkti ir dispatch veiksmams inicijuoti
  // Pavyzdžiui: diapazono įvestis kainai, žymimieji laukeliai prekės ženklams ir kt.

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

Šis pavyzdys parodo, kaip kontroliuotai tvarkyti kelis filtrų kriterijus. Kai vartotojas pakeičia bet kurį filtro nustatymą (kainą, prekės ženklą ir kt.), reducer'is atitinkamai atnaujina filtro būseną. Komponentas, atsakingas už produktų rodymą, naudoja atnaujintą būseną rodomiems produktams filtruoti. Šis šablonas palaiko sudėtingų filtravimo sistemų, būdingų pasaulinėms el. prekybos platformoms, kūrimą.

2. Kelių žingsnių formos (pvz., tarptautinio siuntimo formos)

Daugelis programų apima kelių žingsnių formas, pavyzdžiui, naudojamas tarptautiniam siuntimui ar vartotojų paskyrų su sudėtingais reikalavimais kūrimui. useReducer puikiai tinka tokių formų būsenai valdyti.


import React, { useReducer } from 'react';

const initialState = {
  step: 1, // Dabartinis formos žingsnis
  formData: {
    firstName: '',
    lastName: '',
    address: '',
    city: '',
    country: '',
    // ... kiti formos laukai
  },
  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':
      // Čia tvarkoma formos pateikimo logika, pvz., API užklausos
      return state;
    default:
      return state;
  }
}

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

  // Kiekvieno formos žingsnio atvaizdavimo logika
  // Pagal dabartinį būsenos žingsnį
  const renderStep = () => {
    switch (state.step) {
      case 1:
        return <Step1 formData={state.formData} dispatch={dispatch} />;
      case 2:
        return <Step2 formData={state.formData} dispatch={dispatch} />;
      // ... kiti žingsniai
      default:
        return <p>Neteisingas žingsnis</p>;
    }
  };

  return (
    <div>
      {renderStep()}
      <!-- Navigacijos mygtukai (Kitas, Ankstesnis, Pateikti) pagal dabartinį žingsnį -->
    </div>
  );
}

Tai iliustruoja, kaip struktūrizuotai ir palaikomai valdyti skirtingus formos laukus, žingsnius ir galimas patvirtinimo klaidas. Tai yra labai svarbu kuriant patogius registracijos ar atsiskaitymo procesus, ypač tarptautiniams vartotojams, kurie gali turėti skirtingų lūkesčių, pagrįstų jų vietiniais papročiais ir patirtimi su įvairiomis platformomis, tokiomis kaip Facebook ar WeChat.

3. Realaus laiko programos (pokalbiai, bendradarbiavimo įrankiai)

useReducer yra naudingas realaus laiko programoms, tokioms kaip bendradarbiavimo įrankiai, pavyzdžiui, Google Docs, ar pranešimų siuntimo programos. Jis tvarko įvykius, tokius kaip pranešimų gavimas, vartotojų prisijungimas/išėjimas ir prisijungimo būsena, užtikrindamas, kad vartotojo sąsaja atsinaujintų pagal poreikį.


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(() => {
    // Sukuriame WebSocket ryšį (pavyzdys):
    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(); // Išvalymas atjungiant komponentą
  }, []);

  // Atvaizduojame pranešimus, vartotojų sąrašą ir ryšio būseną pagal būseną
  return (
    <div>
      <p>Ryšio būsena: {state.connectionStatus}</p>
      <!-- UI pranešimams, vartotojų sąrašui rodyti ir pranešimams siųsti -->
    </div>
  );
}

Šis pavyzdys suteikia pagrindą realaus laiko pokalbių valdymui. Būsena tvarko pranešimų saugojimą, pokalbyje esančius vartotojus ir ryšio būseną. useEffect hook'as yra atsakingas už WebSocket ryšio sukūrimą ir gaunamų pranešimų tvarkymą. Šis metodas sukuria reaguojančią ir dinamišką vartotojo sąsają, pritaikytą vartotojams visame pasaulyje.

Geriausios useReducer naudojimo praktikos

Norėdami efektyviai naudoti useReducer ir kurti palaikomas programas, apsvarstykite šias geriausias praktikas:

Išvada

useReducer hook'as yra galingas ir universalus įrankis sudėtingai būsenai valdyti React programose. Jis siūlo daugybę privalumų, įskaitant centralizuotą būsenos logiką, geresnę kodo organizaciją ir padidintą testuojamumą. Laikydamiesi geriausių praktikų ir suprasdami jo pagrindines sąvokas, galite pasinaudoti useReducer, kad sukurtumėte tvirtesnes, palaikomesnes ir našesnes React programas. Šis šablonas suteikia jums galimybę efektyviai spręsti sudėtingus būsenos valdymo iššūkius, leidžiančius kurti globaliam naudojimui skirtas programas, kurios teikia sklandžią vartotojo patirtį visame pasaulyje.

Gilėjant į React kūrimą, useReducer šablono įtraukimas į jūsų įrankių rinkinį neabejotinai padės sukurti švaresnes, labiau išplečiamas ir lengvai prižiūrimas kodo bazes. Visada atsižvelkite į konkrečius savo programos poreikius ir kiekvienai situacijai pasirinkite geriausią būsenos valdymo metodą. Sėkmės programuojant!