Lietuvių

Atraskite pažangius React Context Provider šablonus, skirtus efektyviai valdyti būseną, optimizuoti našumą ir išvengti nereikalingų pervaizdavimų jūsų programose.

React Context Provider šablonai: našumo optimizavimas ir nereikalingų pervaizdavimų išvengimas

React Context API yra galingas įrankis globaliai būsenai (state) valdyti jūsų programose. Jis leidžia dalintis duomenimis tarp komponentų, nereikalaujant rankiniu būdu perduoti „props“ kiekviename lygyje. Tačiau neteisingas Context naudojimas gali sukelti našumo problemų, ypač nereikalingų pervaizdavimų. Šiame straipsnyje nagrinėjami įvairūs Context Provider šablonai, padedantys optimizuoti našumą ir išvengti šių spąstų.

Problemos supratimas: nereikalingi pervaizdavimai

Pagal numatytuosius nustatymus, pasikeitus konteksto vertei, visi komponentai, kurie naudoja tą kontekstą, bus pervaizduojami iš naujo, net jei jie nepriklauso nuo konkrečios pasikeitusios konteksto dalies. Tai gali tapti dideliu našumo butelio kakleliu, ypač didelėse ir sudėtingose programose. Įsivaizduokite scenarijų, kai turite kontekstą, kuriame yra vartotojo informacija, temos nustatymai ir programos parinktys. Jei pasikeičia tik temos nustatymas, idealiu atveju turėtų būti pervaizduojami tik su tema susiję komponentai, o ne visa programa.

Pavyzdžiui, įsivaizduokite globalią el. prekybos programą, prieinamą keliose šalyse. Jei pasikeistų valiutos pasirinkimas (valdomas per kontekstą), nenorėtumėte, kad visas produktų katalogas būtų pervaizduojamas iš naujo – atnaujinti reikia tik kainų rodymą.

1 šablonas: Vertės memoizacija su useMemo

Paprasčiausias būdas išvengti nereikalingų pervaizdavimų yra memoizuoti konteksto vertę naudojant useMemo. Tai užtikrina, kad konteksto vertė pasikeis tik tada, kai pasikeis jos priklausomybės.

Pavyzdys:

Tarkime, turime `UserContext`, kuris teikia vartotojo duomenis ir funkciją vartotojo profiliui atnaujinti.


import React, { createContext, useState, useMemo } from 'react';

const UserContext = createContext(null);

function UserProvider({ children }) {
  const [user, setUser] = useState({
    name: 'John Doe',
    email: 'john.doe@example.com',
    location: 'New York, USA'
  });

  const updateUser = (newUserData) => {
    setUser(prevState => ({ ...prevState, ...newUserData }));
  };

  const contextValue = useMemo(() => ({
    user,
    updateUser,
  }), [user, setUser]);

  return (
    
      {children}
    
  );
}

export { UserContext, UserProvider };

Šiame pavyzdyje useMemo užtikrina, kad `contextValue` pasikeis tik tada, kai pasikeis `user` būsena arba `setUser` funkcija. Jei nei viena, nei kita nepasikeičia, komponentai, naudojantys `UserContext`, nebus pervaizduojami.

Privalumai:

Trūkumai:

2 šablonas: Atsakomybių atskyrimas naudojant kelis kontekstus

Detalesnis požiūris yra padalinti kontekstą į kelis mažesnius kontekstus, kurių kiekvienas atsakingas už tam tikrą būsenos dalį. Tai sumažina pervaizdavimų apimtį ir užtikrina, kad komponentai būtų pervaizduojami tik tada, kai pasikeičia konkretūs duomenys, nuo kurių jie priklauso.

Pavyzdys:

Vietoj vieno `UserContext` galime sukurti atskirus kontekstus vartotojo duomenims ir vartotojo nustatymams.


import React, { createContext, useState } from 'react';

const UserDataContext = createContext(null);
const UserPreferencesContext = createContext(null);

function UserDataProvider({ children }) {
  const [user, setUser] = useState({
    name: 'John Doe',
    email: 'john.doe@example.com',
    location: 'New York, USA'
  });

  const updateUser = (newUserData) => {
    setUser(prevState => ({ ...prevState, ...newUserData }));
  };

  return (
    
      {children}
    
  );
}

function UserPreferencesProvider({ children }) {
  const [theme, setTheme] = useState('light');
  const [language, setLanguage] = useState('en');

  const toggleTheme = () => {
    setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    
      {children}
    
  );
}

export { UserDataContext, UserDataProvider, UserPreferencesContext, UserPreferencesProvider };

Dabar komponentai, kuriems reikia tik vartotojo duomenų, gali naudoti `UserDataContext`, o komponentai, kuriems reikia tik temos nustatymų, gali naudoti `UserPreferencesContext`. Temos pakeitimai nebesukels `UserDataContext` naudojančių komponentų pervaizdavimo ir atvirkščiai.

Privalumai:

Trūkumai:

3 šablonas: Selektorių funkcijos su pasirinktiniais „hooks“

Šis šablonas apima pasirinktinių „hooks“ (custom hooks) kūrimą, kurie ištraukia konkrečias konteksto vertės dalis ir pervaizduoja komponentą tik tada, kai tos konkrečios dalys pasikeičia. Tai ypač naudinga, kai turite didelę konteksto vertę su daug savybių, tačiau komponentui reikia tik kelių iš jų.

Pavyzdys:

Naudodami pradinį `UserContext`, galime sukurti pasirinktinius „hooks“, kad pasirinktume konkrečias vartotojo savybes.


import React, { useContext } from 'react';
import { UserContext } from './UserContext'; // Assuming UserContext is in UserContext.js

function useUserName() {
  const { user } = useContext(UserContext);
  return user.name;
}

function useUserEmail() {
  const { user } = useContext(UserContext);
  return user.email;
}

export { useUserName, useUserEmail };

Dabar komponentas gali naudoti `useUserName`, kad būtų pervaizduotas tik pasikeitus vartotojo vardui, ir `useUserEmail`, kad būtų pervaizduotas tik pasikeitus vartotojo el. pašto adresui. Kitų vartotojo savybių (pvz., vietovės) pakeitimai nesukels pervaizdavimo.


import React from 'react';
import { useUserName, useUserEmail } from './UserHooks';

function UserProfile() {
  const name = useUserName();
  const email = useUserEmail();

  return (
    

Name: {name}

Email: {email}

); }

Privalumai:

Trūkumai:

4 šablonas: Komponento memoizacija su React.memo

React.memo yra aukštesnės eilės komponentas (HOC), kuris memoizuoja funkcinį komponentą. Jis neleidžia komponentui būti pervaizduotam, jei jo „props“ nepasikeitė. Galite tai derinti su kontekstu, kad dar labiau optimizuotumėte našumą.

Pavyzdys:

Tarkime, turime komponentą, kuris rodo vartotojo vardą.


import React, { useContext } from 'react';
import { UserContext } from './UserContext';

function UserName() {
  const { user } = useContext(UserContext);
  return 

Name: {user.name}

; } export default React.memo(UserName);

Apgaubus `UserName` su `React.memo`, jis bus pervaizduojamas tik tada, jei pasikeis `user` „prop“ (netiesiogiai perduotas per kontekstą). Tačiau šiame paprastame pavyzdyje vien `React.memo` neužkirs kelio pervaizdavimui, nes visas `user` objektas vis dar perduodamas kaip „prop“. Kad jis būtų tikrai veiksmingas, jį reikia derinti su selektorių funkcijomis arba atskirais kontekstais.

Efektyvesnis pavyzdys derina `React.memo` su selektorių funkcijomis:


import React from 'react';
import { useUserName } from './UserHooks';

function UserName() {
  const name = useUserName();
  return 

Name: {name}

; } function areEqual(prevProps, nextProps) { // Custom comparison function return prevProps.name === nextProps.name; } export default React.memo(UserName, areEqual);

Čia `areEqual` yra pasirinktinė palyginimo funkcija, kuri tikrina, ar pasikeitė `name` „prop“. Jei nepasikeitė, komponentas nebus pervaizduojamas.

Privalumai:

Trūkumai:

5 šablonas: Konteksto ir „reducers“ derinimas (useReducer)

Konteksto derinimas su useReducer leidžia valdyti sudėtingą būsenos logiką ir optimizuoti pervaizdavimus. useReducer suteikia nuspėjamą būsenos valdymo modelį ir leidžia atnaujinti būseną pagal veiksmus, sumažinant poreikį perduoti kelias nustatymo funkcijas per kontekstą.

Pavyzdys:


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

const UserContext = createContext(null);

const initialState = {
  user: {
    name: 'John Doe',
    email: 'john.doe@example.com',
    location: 'New York, USA'
  },
  theme: 'light',
  language: 'en'
};

const reducer = (state, action) => {
  switch (action.type) {
    case 'UPDATE_USER':
      return { ...state, user: { ...state.user, ...action.payload } };
    case 'TOGGLE_THEME':
      return { ...state, theme: state.theme === 'light' ? 'dark' : 'light' };
    case 'SET_LANGUAGE':
      return { ...state, language: action.payload };
    default:
      return state;
  }
};

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

  return (
    
      {children}
    
  );
}

function useUserState() {
  const { state } = useContext(UserContext);
  return state.user;
}

function useUserDispatch() {
    const { dispatch } = useContext(UserContext);
    return dispatch;
}


export { UserContext, UserProvider, useUserState, useUserDispatch };

Dabar komponentai gali pasiekti būseną ir iškviesti veiksmus naudodami pasirinktinius „hooks“. Pavyzdžiui:


import React from 'react';
import { useUserState, useUserDispatch } from './UserContext';

function UserProfile() {
  const user = useUserState();
  const dispatch = useUserDispatch();

  const handleUpdateName = (e) => {
    dispatch({ type: 'UPDATE_USER', payload: { name: e.target.value } });
  };

  return (
    

Name: {user.name}

); }

Šis šablonas skatina labiau struktūrizuotą požiūrį į būsenos valdymą ir gali supaprastinti sudėtingą konteksto logiką.

Privalumai:

Trūkumai:

6 šablonas: Optimistiniai atnaujinimai

Optimistiniai atnaujinimai apima vartotojo sąsajos atnaujinimą iškart, tarsi veiksmas būtų pavykęs, dar prieš serveriui tai patvirtinant. Tai gali žymiai pagerinti vartotojo patirtį, ypač esant dideliam vėlavimui. Tačiau tai reikalauja kruopštaus galimų klaidų tvarkymo.

Pavyzdys:

Įsivaizduokite programą, kurioje vartotojai gali „patikti“ įrašams. Optimistinis atnaujinimas nedelsiant padidintų „patinka“ skaitiklį, kai vartotojas spusteli mygtuką, ir atšauktų pakeitimą, jei serverio užklausa nepavyktų.


import React, { useContext, useState } from 'react';
import { UserContext } from './UserContext';

function LikeButton({ postId }) {
  const { dispatch } = useContext(UserContext);
  const [isLiking, setIsLiking] = useState(false);

  const handleLike = async () => {
    setIsLiking(true);
    // Optimistically update the like count
    dispatch({ type: 'INCREMENT_LIKES', payload: { postId } });

    try {
      // Simulate an API call
      await new Promise(resolve => setTimeout(resolve, 500));

      // If the API call is successful, do nothing (the UI is already updated)
    } catch (error) {
      // If the API call fails, revert the optimistic update
      dispatch({ type: 'DECREMENT_LIKES', payload: { postId } });
      alert('Failed to like post. Please try again.');
    } finally {
      setIsLiking(false);
    }
  };

  return (
    
  );
}

Šiame pavyzdyje veiksmas `INCREMENT_LIKES` iškviečiamas nedelsiant, o vėliau atšaukiamas, jei API užklausa nepavyksta. Tai suteikia jautresnę vartotojo patirtį.

Privalumai:

Trūkumai:

Tinkamo šablono pasirinkimas

Geriausias Context Provider šablonas priklauso nuo konkrečių jūsų programos poreikių. Štai santrauka, padėsianti pasirinkti:

Papildomi patarimai konteksto našumui optimizuoti

Išvada

React Context API yra galingas įrankis, tačiau svarbu jį naudoti teisingai, kad išvengtumėte našumo problemų. Suprasdami ir taikydami šiame straipsnyje aptartus Context Provider šablonus, galite efektyviai valdyti būseną, optimizuoti našumą ir kurti efektyvesnes bei jautresnes React programas. Nepamirškite išanalizuoti savo konkrečių poreikių ir pasirinkti šabloną, kuris geriausiai atitinka jūsų programos reikalavimus.

Atsižvelgdami į globalią perspektyvą, kūrėjai taip pat turėtų užtikrinti, kad būsenos valdymo sprendimai veiktų sklandžiai skirtingose laiko juostose, valiutų formatuose ir regioniniuose duomenų reikalavimuose. Pavyzdžiui, datos formatavimo funkcija kontekste turėtų būti lokalizuota pagal vartotojo pasirinkimą ar vietą, užtikrinant nuoseklų ir tikslų datų rodymą, nepriklausomai nuo to, iš kur vartotojas pasiekia programą.