Eesti

Avastage Reacti Context Provider'i täiustatud mustreid, et tõhusalt hallata olekut, optimeerida jõudlust ja vältida rakendustes tarbetuid ümberrenderdusi.

Reacti Context Provider'i mustrid: jõudluse optimeerimine ja ümberrenderdamise probleemide vältimine

Reacti Context API on võimas tööriist globaalse oleku haldamiseks teie rakendustes. See võimaldab jagada andmeid komponentide vahel, ilma et peaksite igal tasandil käsitsi prop'e edasi andma. Kuid Contexti vale kasutamine võib põhjustada jõudlusprobleeme, eriti tarbetuid ümberrenderdusi. See artikkel uurib erinevaid Context Provider'i mustreid, mis aitavad teil jõudlust optimeerida ja neid lõkse vältida.

Probleemi mõistmine: tarbetud ümberrenderdused

Vaikimisi, kui Contexti väärtus muutub, renderdatakse uuesti kõik komponendid, mis seda Contexti kasutavad, isegi kui need ei sõltu konkreetsest Contexti osast, mis muutus. See võib olla märkimisväärne jõudluse kitsaskoht, eriti suurtes ja keerukates rakendustes. Kujutage ette stsenaariumi, kus teil on Context, mis sisaldab kasutajateavet, teema seadeid ja rakenduse eelistusi. Kui muutub ainult teema seade, peaksid ideaalis uuesti renderdama ainult teemaga seotud komponendid, mitte kogu rakendus.

Illustreerimiseks kujutage ette globaalset e-kaubanduse rakendust, mis on kättesaadav mitmes riigis. Kui valuuta eelistus muutub (mida hallatakse Contexti kaudu), ei tahaks te, et kogu tootekataloog uuesti renderdataks – värskendamist vajavad ainult hinna kuvad.

Muster 1: Väärtuse memoisatsioon useMemo abil

Lihtsaim lähenemine tarbetute ümberrenderduste vältimiseks on Contexti väärtuse memoisatsioon useMemo abil. See tagab, et Contexti väärtus muutub ainult siis, kui selle sõltuvused muutuvad.

Näide:

Oletame, et meil on `UserContext`, mis pakub kasutajaandmeid ja funktsiooni kasutaja profiili uuendamiseks.


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 };

Selles näites tagab useMemo, et `contextValue` muutub ainult siis, kui `user` olek või `setUser` funktsioon muutub. Kui kumbki ei muutu, siis `UserContext`'i tarbivaid komponente uuesti ei renderdata.

Eelised:

Puudused:

Muster 2: Ülesannete eraldamine mitme Contextiga

Granulaarsem lähenemine on jagada oma Context mitmeks väiksemaks Contextiks, millest igaüks vastutab konkreetse olekuosa eest. See vähendab ümberrenderduste ulatust ja tagab, et komponendid renderdatakse uuesti ainult siis, kui nende sõltuvad andmed muutuvad.

Näide:

Ühe `UserContext`'i asemel saame luua eraldi kontekstid kasutajaandmete ja kasutajaeelistuste jaoks.


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 };

Nüüd saavad komponendid, mis vajavad ainult kasutajaandmeid, tarbida `UserDataContext`'i ja komponendid, mis vajavad ainult teema seadeid, saavad tarbida `UserPreferencesContext`'i. Teema muutused ei põhjusta enam `UserDataContext`'i tarbivate komponentide ümberrenderdamist ja vastupidi.

Eelised:

Puudused:

Muster 3: Selektorfunktsioonid kohandatud hook'idega

See muster hõlmab kohandatud hook'ide loomist, mis eraldavad Contexti väärtusest konkreetsed osad ja renderdavad uuesti ainult siis, kui need konkreetsed osad muutuvad. See on eriti kasulik, kui teil on suur Contexti väärtus paljude omadustega, kuid komponent vajab neist vaid mõnda.

Näide:

Kasutades algset `UserContext`'i, saame luua kohandatud hook'e konkreetsete kasutajaomaduste valimiseks.


import React, { useContext } from 'react';
import { UserContext } from './UserContext'; // Eeldusel, et UserContext on failis UserContext.js

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

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

export { useUserName, useUserEmail };

Nüüd saab komponent kasutada `useUserName`'i, et renderdada uuesti ainult siis, kui kasutaja nimi muutub, ja `useUserEmail`'i, et renderdada uuesti ainult siis, kui kasutaja e-posti aadress muutub. Muudatused teistes kasutajaomadustes (nt asukoht) ei käivita ümberrenderdusi.


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

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

  return (
    

Name: {name}

Email: {email}

); }

Eelised:

Puudused:

Muster 4: Komponendi memoisatsioon React.memo abil

React.memo on kõrgema järgu komponent (HOC), mis memoiseerib funktsionaalse komponendi. See takistab komponendi uuesti renderdamist, kui selle prop'id pole muutunud. Saate seda kombineerida Contextiga, et jõudlust veelgi optimeerida.

Näide:

Oletame, et meil on komponent, mis kuvab kasutaja nime.


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

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

Name: {user.name}

; } export default React.memo(UserName);

Mähkides `UserName`'i `React.memo`'ga, renderdatakse see uuesti ainult siis, kui `user` prop (mis edastatakse kaudselt Contexti kaudu) muutub. Selles lihtsustatud näites ei takista `React.memo` aga üksi ümberrenderdusi, sest kogu `user` objekt edastatakse endiselt prop'ina. Et see oleks tõeliselt tõhus, peate seda kombineerima selektorfunktsioonide või eraldi kontekstidega.

Tõhusam näide ühendab `React.memo` selektorfunktsioonidega:


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

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

Name: {name}

; } function areEqual(prevProps, nextProps) { // Kohandatud võrdlusfunktsioon return prevProps.name === nextProps.name; } export default React.memo(UserName, areEqual);

Siin on `areEqual` kohandatud võrdlusfunktsioon, mis kontrollib, kas `name` prop on muutunud. Kui see pole muutunud, siis komponenti uuesti ei renderdata.

Eelised:

Puudused:

Muster 5: Contexti ja reducer'ite (useReducer) kombineerimine

Contexti kombineerimine useReducer'iga võimaldab hallata keerukat olekuloogikat ja optimeerida ümberrenderdusi. useReducer pakub ettearvatavat olekuhalduse mustrit ja võimaldab teil uuendada olekut toimingute alusel, vähendades vajadust edastada mitut seadistamisfunktsiooni läbi Contexti.

Näide:


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 };

Nüüd saavad komponendid olekule juurde pääseda ja toiminguid saata, kasutades kohandatud hook'e. Näiteks:


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}

); }

See muster edendab struktureeritumat lähenemist olekuhaldusele ja võib lihtsustada keerulist Contexti loogikat.

Eelised:

Puudused:

Muster 6: Optimistlikud uuendused

Optimistlikud uuendused hõlmavad kasutajaliidese kohest uuendamist nii, nagu oleks toiming õnnestunud, isegi enne kui server seda kinnitab. See võib oluliselt parandada kasutajakogemust, eriti suure latentsusega olukordades. Siiski nõuab see võimalike vigade hoolikat käsitlemist.

Näide:

Kujutage ette rakendust, kus kasutajad saavad postitusi meeldivaks märkida. Optimistlik uuendus suurendaks kohe meeldimiste arvu, kui kasutaja klõpsab meeldimisnupul, ja seejärel tühistaks muudatuse, kui serveripäring ebaõnnestub.


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);
    // Uuenda meeldimiste arvu optimistlikult
    dispatch({ type: 'INCREMENT_LIKES', payload: { postId } });

    try {
      // Simuleeri API-kõnet
      await new Promise(resolve => setTimeout(resolve, 500));

      // Kui API-kõne õnnestub, ära tee midagi (kasutajaliides on juba uuendatud)
    } catch (error) {
      // Kui API-kõne ebaõnnestub, tühista optimistlik uuendus
      dispatch({ type: 'DECREMENT_LIKES', payload: { postId } });
      alert('Postituse meeldivaks märkimine ebaõnnestus. Palun proovige uuesti.');
    } finally {
      setIsLiking(false);
    } 
  };

  return (
    
  );
}

Selles näites saadetakse `INCREMENT_LIKES` toiming kohe ja seejärel tühistatakse, kui API-kõne ebaõnnestub. See pakub reageerivamat kasutajakogemust.

Eelised:

Puudused:

Õige mustri valimine

Parim Context Provider'i muster sõltub teie rakenduse konkreetsetest vajadustest. Siin on kokkuvõte, mis aitab teil valida:

Täiendavad näpunäited Contexti jõudluse optimeerimiseks

Kokkuvõte

Reacti Context API on võimas tööriist, kuid jõudlusprobleemide vältimiseks on oluline seda õigesti kasutada. Mõistes ja rakendades selles artiklis käsitletud Context Provider'i mustreid, saate tõhusalt hallata olekut, optimeerida jõudlust ja ehitada tõhusamaid ja reageerivamaid Reacti rakendusi. Pidage meeles, et analüüsige oma konkreetseid vajadusi ja valige muster, mis sobib teie rakenduse nõuetega kõige paremini.

Globaalset perspektiivi arvestades peaksid arendajad tagama ka selle, et olekuhalduse lahendused töötaksid sujuvalt erinevates ajavööndites, valuutavormingutes ja piirkondlikes andmenõuetes. Näiteks Contextis olev kuupäeva vormindamise funktsioon peaks olema lokaliseeritud vastavalt kasutaja eelistusele või asukohale, tagades ühtlase ja täpse kuupäeva kuvamise olenemata sellest, kust kasutaja rakendusele ligi pääseb.