Latviešu

Izpētiet progresīvus React Context Provider modeļus, lai efektīvi pārvaldītu stāvokli, optimizētu veiktspēju un novērstu nevajadzīgas atkārtotas renderēšanas jūsu lietojumprogrammās.

React Context Provider modeļi: veiktspējas optimizēšana un atkārtotas renderēšanas problēmu novēršana

React Context API ir spēcīgs rīks globālā stāvokļa pārvaldībai jūsu lietojumprogrammās. Tas ļauj koplietot datus starp komponentiem, nenododot rekvizītus (props) manuāli katrā līmenī. Tomēr nepareiza Context izmantošana var radīt veiktspējas problēmas, īpaši nevajadzīgu atkārtotu renderēšanu. Šis raksts pēta dažādus Context Provider modeļus, kas palīdz optimizēt veiktspēju un izvairīties no šīm problēmām.

Problēmas izpratne: nevajadzīga atkārtota renderēšana

Pēc noklusējuma, mainoties Context vērtībai, visi komponenti, kas izmanto šo Context, tiks atkārtoti renderēti, pat ja tie nav atkarīgi no konkrētās Context daļas, kas mainījās. Tas var būt nozīmīgs veiktspējas vājais posms, īpaši lielās un sarežģītās lietojumprogrammās. Apsveriet scenāriju, kurā jums ir Context, kas satur lietotāja informāciju, tēmas iestatījumus un lietojumprogrammas preferences. Ja mainās tikai tēmas iestatījums, ideālā gadījumā būtu jāpārrenderē tikai ar tēmu saistītie komponenti, nevis visa lietojumprogramma.

Lai to ilustrētu, iedomājieties globālu e-komercijas lietojumprogrammu, kas pieejama vairākās valstīs. Ja mainās valūtas preference (kas tiek pārvaldīta Context ietvaros), jūs nevēlētos, lai viss produktu katalogs tiktu atkārtoti renderēts – jāatjaunina tikai cenu attēlojums.

1. modelis: vērtības memoizācija ar useMemo

Vienkāršākā pieeja, lai novērstu nevajadzīgu atkārtotu renderēšanu, ir memoizēt Context vērtību, izmantojot useMemo. Tas nodrošina, ka Context vērtība mainās tikai tad, ja mainās tās atkarības.

Piemērs:

Pieņemsim, ka mums ir `UserContext`, kas nodrošina lietotāja datus un funkciju lietotāja profila atjaunināšanai.


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

Šajā piemērā useMemo nodrošina, ka `contextValue` mainās tikai tad, ja mainās `user` stāvoklis vai `setUser` funkcija. Ja nekas no tā nemainās, komponenti, kas izmanto `UserContext`, netiks atkārtoti renderēti.

Ieguvumi:

Trūkumi:

2. modelis: atbildību sadalīšana ar vairākiem Context

Detalizētāka pieeja ir sadalīt jūsu Context vairākos, mazākos Context, no kuriem katrs ir atbildīgs par konkrētu stāvokļa daļu. Tas samazina atkārtotas renderēšanas apjomu un nodrošina, ka komponenti tiek atkārtoti renderēti tikai tad, kad mainās dati, no kuriem tie ir atkarīgi.

Piemērs:

Viena `UserContext` vietā mēs varam izveidot atsevišķus kontekstus lietotāja datiem un lietotāja preferencēm.


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

Tagad komponenti, kuriem nepieciešami tikai lietotāja dati, var izmantot `UserDataContext`, un komponenti, kuriem nepieciešami tikai tēmas iestatījumi, var izmantot `UserPreferencesContext`. Tēmas izmaiņas vairs neizraisīs to komponentu atkārtotu renderēšanu, kas izmanto `UserDataContext`, un otrādi.

Ieguvumi:

Trūkumi:

3. modelis: atlasītāju (selector) funkcijas ar pielāgotiem hooks

Šis modelis ietver pielāgotu "hooks" izveidi, kas iegūst konkrētas Context vērtības daļas un atkārtoti renderē tikai tad, ja mainās šīs konkrētās daļas. Tas ir īpaši noderīgi, ja jums ir liela Context vērtība ar daudzām īpašībām, bet komponentam ir nepieciešamas tikai dažas no tām.

Piemērs:

Izmantojot sākotnējo `UserContext`, mēs varam izveidot pielāgotus "hooks", lai atlasītu konkrētas lietotāja īpašības.


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

Tagad komponents var izmantot `useUserName`, lai atkārtoti renderētu tikai tad, ja mainās lietotāja vārds, un `useUserEmail`, lai atkārtoti renderētu tikai tad, ja mainās lietotāja e-pasts. Izmaiņas citās lietotāja īpašībās (piem., atrašanās vietā) neizraisīs atkārtotu renderēšanu.


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

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

  return (
    

Name: {name}

Email: {email}

); }

Ieguvumi:

Trūkumi:

4. modelis: komponentu memoizācija ar React.memo

React.memo ir augstākas kārtas komponents (HOC), kas memoizē funkcionālu komponentu. Tas neļauj komponentam atkārtoti renderēties, ja tā rekvizīti (props) nav mainījušies. To var apvienot ar Context, lai vēl vairāk optimizētu veiktspēju.

Piemērs:

Pieņemsim, ka mums ir komponents, kas parāda lietotāja vārdu.


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

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

Name: {user.name}

; } export default React.memo(UserName);

Ietverot `UserName` ar `React.memo`, tas atkārtoti renderēsies tikai tad, ja mainīsies `user` rekvizīts (netieši nodots caur Context). Tomēr šajā vienkāršotajā piemērā `React.memo` pats par sevi nenovērsīs atkārtotu renderēšanu, jo viss `user` objekts joprojām tiek nodots kā rekvizīts. Lai tas būtu patiesi efektīvs, tas jāapvieno ar atlasītāju funkcijām vai atsevišķiem kontekstiem.

Efektīvāks piemērs apvieno `React.memo` ar atlasītāju funkcijām:


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

Šeit `areEqual` ir pielāgota salīdzināšanas funkcija, kas pārbauda, vai `name` rekvizīts ir mainījies. Ja tas nav mainījies, komponents netiks atkārtoti renderēts.

Ieguvumi:

Trūkumi:

5. modelis: Context un reduceru apvienošana (useReducer)

Context apvienošana ar useReducer ļauj pārvaldīt sarežģītu stāvokļa loģiku un optimizēt atkārtotu renderēšanu. useReducer nodrošina paredzamu stāvokļa pārvaldības modeli un ļauj atjaunināt stāvokli, pamatojoties uz darbībām, samazinot nepieciešamību nodot vairākas stāvokļa iestatīšanas funkcijas caur Context.

Piemērs:


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

Tagad komponenti var piekļūt stāvoklim un nosūtīt darbības, izmantojot pielāgotus "hooks". Piemēram:


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 modelis veicina strukturētāku pieeju stāvokļa pārvaldībai un var vienkāršot sarežģītu Context loģiku.

Ieguvumi:

Trūkumi:

6. modelis: optimistiskie atjauninājumi

Optimistiskie atjauninājumi ietver lietotāja saskarnes (UI) tūlītēju atjaunināšanu tā, it kā darbība būtu bijusi veiksmīga, pat pirms serveris to apstiprina. Tas var ievērojami uzlabot lietotāja pieredzi, īpaši situācijās ar lielu latentumu. Tomēr tas prasa rūpīgu potenciālo kļūdu apstrādi.

Piemērs:

Iedomājieties lietojumprogrammu, kurā lietotāji var atzīmēt ziņas ar "patīk". Optimistisks atjauninājums nekavējoties palielinātu "patīk" skaitu, kad lietotājs noklikšķina uz "patīk" pogas, un pēc tam atceltu izmaiņas, ja servera pieprasījums neizdodas.


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

Šajā piemērā darbība `INCREMENT_LIKES` tiek nosūtīta nekavējoties un pēc tam atcelta, ja API pieprasījums neizdodas. Tas nodrošina atsaucīgāku lietotāja pieredzi.

Ieguvumi:

Trūkumi:

Pareizā modeļa izvēle

Labākais Context Provider modelis ir atkarīgs no jūsu lietojumprogrammas konkrētajām vajadzībām. Šeit ir kopsavilkums, kas palīdzēs jums izvēlēties:

Papildu padomi Context veiktspējas optimizēšanai

Noslēgums

React Context API ir spēcīgs rīks, taču ir svarīgi to pareizi izmantot, lai izvairītos no veiktspējas problēmām. Izprotot un pielietojot šajā rakstā apskatītos Context Provider modeļus, jūs varat efektīvi pārvaldīt stāvokli, optimizēt veiktspēju un veidot efektīvākas un atsaucīgākas React lietojumprogrammas. Atcerieties analizēt savas konkrētās vajadzības un izvēlēties modeli, kas vislabāk atbilst jūsu lietojumprogrammas prasībām.

Raugoties no globālas perspektīvas, izstrādātājiem būtu arī jānodrošina, ka stāvokļa pārvaldības risinājumi nevainojami darbojas dažādās laika joslās, valūtu formātos un reģionālajās datu prasībās. Piemēram, datuma formatēšanas funkcijai Context ietvaros jābūt lokalizētai atbilstoši lietotāja preferencei vai atrašanās vietai, nodrošinot konsekventus un precīzus datuma attēlojumus neatkarīgi no tā, no kurienes lietotājs piekļūst lietojumprogrammai.