Latviešu

Iedziļinieties React useReducer hūkā, lai efektīvi pārvaldītu sarežģītus aplikāciju stāvokļus, uzlabojot veiktspēju un uzturamību globālos React projektos.

React useReducer paterns: sarežģītas stāvokļa pārvaldības apgūšana

Pastāvīgi mainīgajā front-end izstrādes vidē React ir nostiprinājies kā vadošais ietvars lietotāja saskarņu veidošanai. Aplikācijām kļūstot sarežģītākām, stāvokļa pārvaldība kļūst arvien lielāks izaicinājums. useState hūks nodrošina vienkāršu veidu, kā pārvaldīt stāvokli komponentes ietvaros, bet sarežģītākiem scenārijiem React piedāvā jaudīgu alternatīvu: useReducer hūku. Šis emuāra ieraksts iedziļinās useReducer paternā, pētot tā priekšrocības, praktiskās implementācijas un to, kā tas var būtiski uzlabot jūsu React aplikācijas globālā mērogā.

Izpratne par nepieciešamību pēc sarežģītas stāvokļa pārvaldības

Veidojot React aplikācijas, mēs bieži saskaramies ar situācijām, kurās komponentes stāvoklis nav tikai vienkārša vērtība, bet gan savstarpēji saistītu datu punktu kopums vai stāvoklis, kas atkarīgs no iepriekšējām stāvokļa vērtībām. Apsveriet šādus piemērus:

Šajos scenārijos, izmantojot tikai useState, kods var kļūt sarežģīts un grūti pārvaldāms. Var kļūt apgrūtinoši atjaunināt vairākus stāvokļa mainīgos, reaģējot uz vienu notikumu, un šo atjauninājumu pārvaldības loģika var kļūt izkliedēta pa visu komponenti, padarot to grūti saprotamu un uzturamu. Tieši šeit useReducer sevi pierāda.

Iepazīstinām ar useReducer hūku

useReducer hūks ir alternatīva useState, lai pārvaldītu sarežģītu stāvokļa loģiku. Tas ir balstīts uz Redux paterna principiem, bet tiek ieviests pašā React komponentē, daudzos gadījumos novēršot nepieciešamību pēc atsevišķas ārējas bibliotēkas. Tas ļauj centralizēt jūsu stāvokļa atjaunināšanas loģiku vienā funkcijā, ko sauc par reduceru.

useReducer hūks pieņem divus argumentus:

Hūks atgriež masīvu ar diviem elementiem:

Reducera funkcija

Reducera funkcija ir useReducer paterna sirds. Tā ir tīra funkcija, kas nozīmē, ka tai nevajadzētu būt blakusefektiem (piemēram, veikt API izsaukumus vai modificēt globālus mainīgos) un tai vienmēr jāatgriež tāds pats rezultāts tiem pašiem ievades datiem. Reducera funkcija pieņem divus argumentus:

Reducera funkcijas iekšienē jūs izmantojat switch priekšrakstu vai if/else if priekšrakstus, lai apstrādātu dažādus darbību tipus un atbilstoši atjauninātu stāvokli. Tas centralizē jūsu stāvokļa atjaunināšanas loģiku un atvieglo izpratni par to, kā stāvoklis mainās, reaģējot uz dažādiem notikumiem.

Dispatch funkcija

Dispatch funkcija ir metode, ko izmantojat, lai izraisītu stāvokļa atjauninājumus. Kad jūs izsaucat dispatch(action), darbība tiek nodota reducera funkcijai, kas pēc tam atjaunina stāvokli, pamatojoties uz darbības tipu un payload.

Praktisks piemērs: skaitītāja ieviešana

Sāksim ar vienkāršu piemēru: skaitītāja komponente. Tas ilustrē pamatkoncepcijas, pirms pāriet pie sarežģītākiem piemēriem. Mēs izveidosim skaitītāju, kas var palielināt, samazināt un atiestatīt vērtību:


import React, { useReducer } from 'react';

// Definēt darbību tipus
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
const RESET = 'RESET';

// Definēt reducera funkciju
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() {
  // Inicializēt useReducer
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });

  return (
    <div>
      <p>Skaits: {state.count}</p>
      <button onClick={() => dispatch({ type: INCREMENT })}>Palielināt</button>
      <button onClick={() => dispatch({ type: DECREMENT })}>Samazināt</button>
      <button onClick={() => dispatch({ type: RESET })}>Atiestatīt</button>
    </div>
  );
}

export default Counter;

Šajā piemērā:

Skaitītāja piemēra paplašināšana: Payload pievienošana

Pārveidosim skaitītāju, lai atļautu palielināt vērtību par noteiktu skaitli. Tas ievieš payload konceptu darbībā:


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>Skaits: {state.count}</p>
      <button onClick={() => dispatch({ type: INCREMENT, payload: parseInt(inputValue) || 1 })}>Palielināt par {inputValue}</button>
      <button onClick={() => dispatch({ type: DECREMENT, payload: parseInt(inputValue) || 1 })}>Samazināt par {inputValue}</button>
      <button onClick={() => dispatch({ type: RESET })}>Atiestatīt</button>
       <input
         type="number"
         value={inputValue}
         onChange={(e) => setInputValue(e.target.value)}
       />
      </div>
  );
}

export default Counter;

Šajā paplašinātajā piemērā:

useReducer izmantošanas priekšrocības

useReducer paterns piedāvā vairākas priekšrocības salīdzinājumā ar useState tiešu izmantošanu sarežģītai stāvokļa pārvaldībai:

Kad izmantot useReducer

Lai gan useReducer piedāvā ievērojamas priekšrocības, tā ne vienmēr ir pareizā izvēle. Apsveriet useReducer izmantošanu, ja:

Vienkāršiem stāvokļa atjauninājumiem useState bieži vien ir pietiekams un vienkāršāk lietojams. Pieņemot lēmumu, apsveriet sava stāvokļa sarežģītību un potenciālo izaugsmi.

Padziļināti koncepti un tehnikas

useReducer apvienošana ar Context

Lai pārvaldītu globālo stāvokli vai koplietotu stāvokli starp vairākām komponentēm, varat apvienot useReducer ar React Context API. Šī pieeja bieži tiek dota priekšroka salīdzinājumā ar Redux mazākiem un vidējiem projektiem, kur nevēlaties ieviest papildu atkarības.


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

// Definēt darbību tipus un reduceru (kā iepriekš)
const INCREMENT = 'INCREMENT';
// ... (citi darbību tipi un 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>Skaits: {state.count}</p>
      <button onClick={() => dispatch({ type: INCREMENT })}>Palielināt</button>
    </div>
  );
}

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

export default App;

Šajā piemērā:

useReducer testēšana

Reduceru testēšana ir vienkārša, jo tās ir tīras funkcijas. Jūs varat viegli testēt reducera funkciju izolēti, izmantojot vienībtestēšanas ietvaru, piemēram, Jest vai Mocha. Šeit ir piemērs, izmantojot Jest:


import { counterReducer } from './counterReducer'; // Pieņemot, ka counterReducer atrodas atsevišķā failā

const INCREMENT = 'INCREMENT';

describe('counterReducer', () => {
  it('jāpalielina skaitītājs', () => {
    const state = { count: 0 };
    const action = { type: INCREMENT };
    const newState = counterReducer(state, action);
    expect(newState.count).toBe(1);
  });

   it('jāatgriež tas pats stāvoklis nezināmiem darbību tipiem', () => {
        const state = { count: 10 };
        const action = { type: 'UNKNOWN_ACTION' };
        const newState = counterReducer(state, action);
        expect(newState).toBe(state); // Pārbaudīt, ka stāvoklis nav mainījies
    });
});

Reduceru testēšana nodrošina, ka tie darbojas, kā paredzēts, un atvieglo stāvokļa loģikas pārveidošanu. Tas ir kritisks solis, veidojot stabilas un uzturamas aplikācijas.

Veiktspējas optimizācija ar memoizāciju

Strādājot ar sarežģītiem stāvokļiem un biežiem atjauninājumiem, apsveriet iespēju izmantot useMemo, lai optimizētu savu komponenšu veiktspēju, īpaši, ja jums ir atvasinātas vērtības, kas tiek aprēķinātas, pamatojoties uz stāvokli. Piemēram:


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

function reducer(state, action) {
  // ... (reducera loģika) 
}

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

  // Aprēķināt atvasināto vērtību, memoizējot to ar useMemo
  const derivedValue = useMemo(() => {
    // Dārgs aprēķins, kas balstīts uz stāvokli
    return state.value1 + state.value2;
  }, [state.value1, state.value2]); // Atkarības: pārrēķināt tikai tad, kad mainās šīs vērtības

  return (
    <div>
      <p>Atvasinātā vērtība: {derivedValue}</p>
      <button onClick={() => dispatch({ type: 'UPDATE_VALUE1', payload: 10 })}>Atjaunināt vērtību 1</button>
      <button onClick={() => dispatch({ type: 'UPDATE_VALUE2', payload: 20 })}>Atjaunināt vērtību 2</button>
    </div>
  );
}

Šajā piemērā derivedValue tiek aprēķināta tikai tad, kad mainās state.value1 vai state.value2, novēršot nevajadzīgus aprēķinus katrā atkārtotā renderēšanā. Šī pieeja ir izplatīta prakse, lai nodrošinātu optimālu renderēšanas veiktspēju.

Reālās pasaules piemēri un pielietojuma gadījumi

Apskatīsim dažus praktiskus piemērus, kur useReducer ir vērtīgs rīks, veidojot React aplikācijas globālai auditorijai. Ņemiet vērā, ka šie piemēri ir vienkāršoti, lai ilustrētu pamatkoncepcijas. Faktiskās implementācijas var ietvert sarežģītāku loģiku un atkarības.

1. E-komercijas produktu filtri

Iedomājieties e-komercijas vietni (piemēram, populāras platformas kā Amazon vai AliExpress, kas pieejamas visā pasaulē) ar lielu produktu katalogu. Lietotājiem ir nepieciešams filtrēt produktus pēc dažādiem kritērijiem (cenu diapazons, zīmols, izmērs, krāsa, izcelsmes valsts utt.). useReducer ir ideāli piemērots filtru stāvokļa pārvaldībai.


import React, { useReducer } from 'react';

const initialState = {
  priceRange: { min: 0, max: 1000 },
  brand: [], // Atlasīto zīmolu masīvs
  color: [], // Atlasīto krāsu masīvs
  //... citi filtru kritēriji
};

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':
      // Līdzīga loģika krāsu filtrēšanai
      return { ...state, color: state.color.includes(action.payload) ? state.color.filter(c => c !== action.payload) : [...state.color, action.payload] };
    // ... citas filtru darbības
    default:
      return state;
  }
}

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

  // UI komponentes filtru kritēriju izvēlei un dispatch darbību izsaukšanai
  // Piemēram: diapazona ievade cenai, izvēles rūtiņas zīmoliem utt.

  return (
    <div>
      <!-- Filtra UI elementi -->
    </div>
  );
}

Šis piemērs parāda, kā kontrolēti apstrādāt vairākus filtru kritērijus. Kad lietotājs modificē jebkuru filtra iestatījumu (cenu, zīmolu utt.), reducers atbilstoši atjaunina filtra stāvokli. Komponente, kas atbild par produktu attēlošanu, pēc tam izmanto atjaunināto stāvokli, lai filtrētu attēlotos produktus. Šis paterns atbalsta sarežģītu filtrēšanas sistēmu izveidi, kas ir izplatītas globālās e-komercijas platformās.

2. Vairāku soļu formas (piemēram, starptautiskās piegādes formas)

Daudzās aplikācijās ir vairāku soļu formas, piemēram, tās, ko izmanto starptautiskai piegādei vai lietotāju kontu izveidei ar sarežģītām prasībām. useReducer lieliski tiek galā ar šādu formu stāvokļa pārvaldību.


import React, { useReducer } from 'react';

const initialState = {
  step: 1, // Pašreizējais solis formā
  formData: {
    firstName: '',
    lastName: '',
    address: '',
    city: '',
    country: '',
    // ... citi formas lauki
  },
  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':
      // Šeit apstrādājiet formas iesniegšanas loģiku, piem., API izsaukumus
      return state;
    default:
      return state;
  }
}

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

  // Katra formas soļa renderēšanas loģika
  // Balstoties uz pašreizējo stāvokļa soli
  const renderStep = () => {
    switch (state.step) {
      case 1:
        return <Step1 formData={state.formData} dispatch={dispatch} />;
      case 2:
        return <Step2 formData={state.formData} dispatch={dispatch} />;
      // ... citi soļi
      default:
        return <p>Nederīgs solis</p>;
    }
  };

  return (
    <div>
      {renderStep()}
      <!-- Navigācijas pogas (Nākamais, Iepriekšējais, Iesniegt), balstoties uz pašreizējo soli -->
    </div>
  );
}

Tas ilustrē, kā strukturētā un uzturamā veidā pārvaldīt dažādus formas laukus, soļus un iespējamās validācijas kļūdas. Tas ir kritiski svarīgi, lai izveidotu lietotājam draudzīgus reģistrācijas vai apmaksas procesus, īpaši starptautiskiem lietotājiem, kuriem var būt atšķirīgas gaidas, pamatojoties uz vietējām paražām un pieredzi ar dažādām platformām, piemēram, Facebook vai WeChat.

3. Reāllaika aplikācijas (tērzēšana, sadarbības rīki)

useReducer ir noderīgs reāllaika aplikācijām, piemēram, sadarbības rīkiem kā Google Docs vai ziņojumapmaiņas aplikācijām. Tas apstrādā tādus notikumus kā ziņojumu saņemšana, lietotāja pievienošanās/aiziešana un savienojuma statuss, nodrošinot, ka UI tiek atjaunināts pēc nepieciešamības.


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(() => {
    // Izveidot WebSocket savienojumu (piemērs):
    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(); // Tīrīšana, atvienojot komponenti
  }, []);

  // Renderēt ziņojumus, lietotāju sarakstu un savienojuma statusu, balstoties uz stāvokli
  return (
    <div>
      <p>Savienojuma statuss: {state.connectionStatus}</p>
      <!-- UI ziņojumu attēlošanai, lietotāju sarakstam un ziņojumu sūtīšanai -->
    </div>
  );
}

Šis piemērs nodrošina pamatu reāllaika tērzēšanas pārvaldībai. Stāvoklis apstrādā ziņojumu glabāšanu, lietotājus, kas pašlaik atrodas tērzētavā, un savienojuma statusu. useEffect hūks ir atbildīgs par WebSocket savienojuma izveidi un ienākošo ziņojumu apstrādi. Šī pieeja rada atsaucīgu un dinamisku lietotāja saskarni, kas apmierina lietotājus visā pasaulē.

Labākās prakses useReducer izmantošanai

Lai efektīvi izmantotu useReducer un veidotu uzturamas aplikācijas, ievērojiet šīs labākās prakses:

Noslēgums

useReducer hūks ir jaudīgs un daudzpusīgs rīks sarežģītu stāvokļu pārvaldībai React aplikācijās. Tas piedāvā daudzas priekšrocības, tostarp centralizētu stāvokļa loģiku, uzlabotu koda organizāciju un paaugstinātu testējamību. Ievērojot labākās prakses un izprotot tā pamatkoncepcijas, jūs varat izmantot useReducer, lai veidotu stabilākas, uzturamas un veiktspējīgākas React aplikācijas. Šis paterns dod jums iespēju efektīvi risināt sarežģītus stāvokļa pārvaldības izaicinājumus, ļaujot jums veidot globāli gatavas aplikācijas, kas nodrošina nevainojamu lietotāja pieredzi visā pasaulē.

Iedziļinoties React izstrādē, useReducer paterna iekļaušana savā rīku komplektā neapšaubāmi novedīs pie tīrākiem, mērogojamākiem un vieglāk uzturamiem kodiem. Atcerieties vienmēr apsvērt savas aplikācijas specifiskās vajadzības un izvēlēties labāko stāvokļa pārvaldības pieeju katrai situācijai. Veiksmīgu kodēšanu!