React.js useEffect срещу (componentDidMount, componentDidUpdate и componentWillUnmount)

В наши дни има много предни библиотеки и рамки. Най-популярните от тях са React.js, Angular.js и Vue.js. Всеки един от тях има собствено място в индустрията. И хората ги харесват много заради способността им да изобразяват и манипулират DOM по време на изпълнение. Те могат да направят това, като поддържат състоянието на компонентите на приложението. Днес ще говорим за React и методите за неговия жизнен цикъл.

React е популярна предна JavaScript библиотека за изграждане на потребителски интерфейси и предоставя редица функции и инструменти, за да направи разработката по-лесна и по-ефективна. Един от най-важните аспекти на React е управлението на жизнения цикъл на компонентите, което може да окаже значително влияние върху производителността, стабилността и потребителското изживяване.

В тази публикация в блога ще проучим разликите между useEffect и методите на жизнения цикъл на компонентите на класа (componentDidMount, componentDidUpdate и componentWillUnmount) и ще обясним кога и защо можете да изберете да използвате един пред друг. Като разберете тези разлики, вие ще можете да пишете по-ефективен и ефективен код на React, който осигурява по-добри резултати за вашите потребители.

componentDidMount:

componentDidMount е метод на жизнения цикъл в компонентите на клас React, който се извиква веднъж, веднага след монтиране на компонент (т.е. вмъкване в DOM). Това го прави добро място за извършване на първоначална настройка, която изисква достъп до DOM или външни източници на данни, като извличане на данни от сървър или инициализиране на библиотека на трета страна.

Когато се извика componentDidMount, реквизитите и състоянието на компонента вече са зададени и методът за изобразяване на компонента е извикан, което означава, че всички дъщерни компоненти също са монтирани. Това го прави безопасно място за извършване на всички необходими операции, които зависят от дъщерните или родителските компоненти на компонента.

Важно е да се отбележи, че componentDidMount се извиква само веднъж през живота на компонента. След първоначалното монтиране следващите актуализации на компонента няма да задействат componentDidMount. Ако трябва да извършите актуализации или почистване след първоначалното монтиране, вместо това трябва да използвате метода на жизнения цикъл componentDidUpdate.

Пример:

import React, { Component } from 'react';

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: null,
    };
  }

  componentDidMount() {
    // Fetch data from a server after the component has mounted
    fetch('https://example.com/data')
      .then(response => response.json())
      .then(data => this.setState({ data }));
  }

  render() {
    return (
      <div>
        {/* Render the data once it has been fetched */}
        {this.state.data && <p>{this.state.data}</p>}
      </div>
    );
  }
}

В този пример класът MyComponent разширява Component и дефинира обект на състояние със свойство data, инициализирано на null. В метода componentDidMount компонентът използва fetch API за асинхронно извличане на данни от сървър и след това задава свойството data в състояние с помощта на this.setState. След като данните бъдат извлечени и поставени в състояние, методът render на компонента ще бъде извикан отново, този път изобразявайки извлечените данни.

componentDidMount срещу useEffect:

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

function MyComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    // Fetch data from a server after the component has mounted
    fetch('https://example.com/data')
      .then(response => response.json())
      .then(data => setData(data));
  }, []); // Empty dependency array ensures the effect runs only once, like componentDidMount

  return (
    <div>
      {/* Render the data once it has been fetched */}
      {data && <p>{data}</p>}
    </div>
  );
}

В този пример функцията MyComponent дефинира променлива на състоянието data, инициализирана на null, и използва куката useEffect за извличане на данни от сървър, след като компонентът е монтиран. Вторият аргумент на useEffect е празен масив, който гарантира, че ефектът се изпълнява само веднъж, имитирайки поведението на componentDidMount. След като данните бъдат извлечени и зададени с помощта на функцията setData, компонентът ще изобрази отново, този път изобразявайки извлечените данни.

componentDidUpdate:

componentDidUpdate е метод на жизнения цикъл в компонентите на клас React, който се извиква след актуализиране на компонент и се изобразява повторно в DOM. Този метод е полезен за извършване на всякакви странични ефекти, които зависят от промените в подпорите или състоянието на компонента.

Когато се извика componentDidUpdate, предишните характеристики и състояние на компонента могат да бъдат достъпни с помощта на обектите this.props и this.state, а текущите характеристики и състояние могат да бъдат достъпни с помощта на аргументите nextProps и nextState, предадени на метода.

Важно е да се отбележи, че componentDidUpdate се извиква след всяка актуализация на компонента, включително първоначалното монтиране. Следователно трябва да се уверите, че сте проверили дали съответните реквизити или състояние действително са се променили, преди да извършите каквито и да е скъпи операции или да задействате друга актуализация, за да избегнете причиняването на ненужни повторни изобразявания или безкрайни цикли.

Ако трябва да актуализирате състоянието в отговор на промени в реквизитите, трябва вместо това да използвате метода static getDerivedStateFromProps, тъй като той се извиква преди render и не предизвиква допълнително повторно изобразяване.

Пример:

import React, { Component } from 'react';

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }

  componentDidUpdate(prevProps, prevState) {
    // Log the previous and current count values when the count changes
    if (this.state.count !== prevState.count) {
      console.log(`Count changed from ${prevState.count} to ${this.state.count}`);
    }
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Increment Count
        </button>
      </div>
    );
  }
}

В този пример класът MyComponent разширява Component и дефинира обект на състояние със свойство count, инициализирано на 0. В метода componentDidUpdate компонентът проверява дали текущата стойност count е различна от предишната стойност count, съхранена в prevState, и записва съобщение в конзолата, ако се е променила.

Методът render на компонента изобразява текущата стойност count и бутон, който актуализира броя при щракване. Всеки път, когато стойността count се актуализира, компонентът ще се визуализира отново и componentDidUpdate ще бъде извикан, като се регистрира съобщение в конзолата, ако стойността count се е променила.

componentDidUpdate срещу useEffect:

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

function MyComponent(props) {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // Log the previous and current count values when the count changes
    console.log(`Count changed from ${prevCount} to ${count}`);
  }, [count]); // Run the effect whenever the count changes

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment Count</button>
    </div>
  );
}

В този пример функцията MyComponent дефинира променлива на състоянието count, инициализирана на 0, и използва куката useEffect, за да регистрира съобщение в конзолата всеки път, когато броячът се промени. Вторият аргумент на useEffect е масив, съдържащ променливата count, която гарантира, че ефектът се изпълнява само когато броячът се промени, имитирайки поведението на componentDidUpdate.

Функцията handleClick актуализира броя, като извиква функцията setCount с текущия брой плюс 1. Когато броят се актуализира, компонентът ще се изобрази отново, задействайки куката useEffect да се изпълни и да регистрира съобщение в конзолата, ако броячът се е променил.

componentWillUnmount:

componentWillUnmount е метод на жизнения цикъл в компонентите на клас React, който се извиква точно преди даден компонент да бъде демонтиран и премахнат от DOM. Този метод е полезен за извършване на всички необходими операции за почистване или премахване, като отмяна на таймери, премахване на слушатели на събития или изчистване на данни от кеш.

Когато се извика componentWillUnmount, компонентът трябва да изчисти всички ресурси, които са били създадени или използвани по време на неговия жизнен цикъл. Ако компонентът е настроил някакви абонаменти или слушатели в метода componentDidMount например, той трябва да ги премахне в componentWillUnmount, за да избегне изтичане на памет или нежелани странични ефекти.

Важно е да се отбележи, че componentWillUnmount се извиква само веднъж, когато компонентът се демонтира. Следователно това е добро място за извършване на всякакви операции за почистване, които трябва да се случват само веднъж, вместо в componentDidUpdate, което се извиква след всяка актуализация.

Пример:

import React, { Component } from 'react';

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
    this.timerId = null;
  }

  componentDidMount() {
    // Start a timer that updates the count every second
    this.timerId = setInterval(() => {
      this.setState({ count: this.state.count + 1 });
    }, 1000);
  }

  componentWillUnmount() {
    // Clean up the timer before the component is unmounted
    clearInterval(this.timerId);
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
      </div>
    );
  }
}

В този пример класът MyComponent разширява Component и дефинира обект на състояние със свойство count, инициализирано на 0. В метода componentDidMount компонентът стартира таймер, който актуализира броя всяка секунда и съхранява идентификатора на таймера в this.timerId.

В метода componentWillUnmount компонентът изчиства таймера с помощта на clearInterval, за да предотврати продължаването му да работи, след като компонентът бъде демонтиран.

Методът render на компонента изобразява текущата стойност count. Когато компонентът е демонтиран, componentWillUnmount се извиква за почистване на таймера и предотвратяване на по-нататъшни актуализации на състоянието.

componentWillUnmount срещу useEffect:

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

function MyComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const timerId = setInterval(() => {
      setCount(count => count + 1);
    }, 1000);

    return () => {
      clearInterval(timerId);
    };
  }, []); // Run the effect only once on mount

  return (
    <div>
      <p>Count: {count}</p>
    </div>
  );
}

В този пример функцията MyComponent използва useEffect, за да стартира таймер, който актуализира променливата на състоянието count всяка секунда. Куката useEffect връща функция за почистване, която изчиства таймера с помощта на clearInterval.

Празният масив на зависимости ([]), подаден като втори аргумент на useEffect, гарантира, че ефектът се изпълнява само веднъж, когато компонентът се монтира, вместо да се изпълнява при всяка актуализация.

Когато компонентът е демонтиран, се извиква функцията за почистване, върната от useEffect, която изчиства таймера, за да предотврати по-нататъшни актуализации на състоянието.

Като използваме useEffect за обработка на операции за почистване, можем да избегнем необходимостта да дефинираме отделен метод componentWillUnmount в компонентите на класа и да направим нашия код по-сбит и четим.

useEffect:

Във функционалните компоненти куката useEffect може да се използва за постигане на същата функционалност като методите на жизнения цикъл на компонентите на класа. Куката useEffect приема функция като първи аргумент и изпълнява тази функция, след като компонентът е изобразен. Функцията може да върне функция за почистване, която ще бъде извикана, когато компонентът се демонтира.

Ключови разлики:

Ето някои ключови разлики между useEffect куката и методите на жизнения цикъл на компонента на класа:

  • useEffect замества трите метода на жизнения цикъл на компонентите на класа с една кука.
  • За разлика от componentDidMount, куката useEffect се изпълнява след всяко изобразяване на компонента (освен ако към куката не бъде подаден втори аргумент, за да се укаже кога да се стартира отново).
  • useEffect няма пряк еквивалент на componentDidUpdate, но може да се използва за постигане на същата функционалност чрез включване на съответното състояние или реквизити в масива на зависимости, подаден като втори аргумент на useEffect.
  • Функцията за почистване, върната от useEffect, е подобна по функционалност на componentWillUnmount, но се изпълнява след всяко изобразяване, а не само когато компонентът се демонтира.

„Благодаря ви, че прочетохте! Ако тази публикация ви е харесала, не забравяйте да разгледате някои от моите други статии. Можете също така да ме намерите в LinkedIn, където можем да водим по-подробни разговори и можете да ми препоръчате промени или нови теми, които трябва да добавя. Нека се свържем и да продължим разговора!'