useEffect

useEffect என்பது ஒரு component-ஐ external system உடன் synchronize செய்ய அனுமதிக்கும் React Hook.

useEffect(setup, dependencies?)

Reference

useEffect(setup, dependencies?)

Effect ஒன்றை declare செய்ய உங்கள் component-ன் top level-இல் useEffect call செய்யுங்கள்:

import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';

function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');

useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}

மேலும் examples கீழே பார்க்கவும்.

Parameters

  • setup: உங்கள் Effect-ன் logic கொண்ட function. உங்கள் setup function optional ஆக ஒரு cleanup function-ஐ return செய்யலாம். உங்கள் component commit ஆனதும், React உங்கள் setup function-ஐ run செய்யும். Dependencies மாறிய ஒவ்வொரு commit-க்கும் பிறகு, React முதலில் பழைய values உடன் cleanup function-ஐ (நீங்கள் கொடுத்திருந்தால்) run செய்து, பிறகு புதிய values உடன் setup function-ஐ run செய்யும். உங்கள் component DOM-இலிருந்து remove செய்யப்பட்ட பிறகு, React உங்கள் cleanup function-ஐ run செய்யும்.

  • optional dependencies: setup code-க்குள் referenced ஆன எல்லா reactive values-ன் list. Reactive values-இல் props, state, மற்றும் உங்கள் component body-க்குள் நேரடியாக declared செய்யப்பட்ட எல்லா variables மற்றும் functions அடங்கும். உங்கள் linter React-க்காக configured செய்யப்பட்டிருந்தால், ஒவ்வொரு reactive value-உம் dependency ஆக சரியாக specified உள்ளதா என்று verify செய்யும். Dependencies list-இல் constant number of items இருக்க வேண்டும்; மேலும் [dep1, dep2, dep3] போல inline ஆக எழுதப்பட வேண்டும். React ஒவ்வொரு dependency-யையும் அதன் previous value உடன் Object.is comparison பயன்படுத்தி compare செய்யும். இந்த argument-ஐ omit செய்தால், component-ன் ஒவ்வொரு commit-க்கும் பிறகு உங்கள் Effect re-run ஆகும். Dependencies array, empty array, மற்றும் dependency ஏதும் இல்லாமல் pass செய்வதின் வேறுபாட்டைப் பார்க்கவும்.

Returns

useEffect undefined return செய்கிறது.

Caveats

  • useEffect ஒரு Hook என்பதால், அதை உங்கள் component-ன் top level அல்லது உங்கள் சொந்த Hooks-இல் மட்டுமே call செய்யலாம். Loops அல்லது conditions-க்குள் call செய்ய முடியாது. அது தேவைப்பட்டால், புதிய component ஒன்றை extract செய்து state-ஐ அதற்குள் move செய்யுங்கள்.

  • நீங்கள் ஏதாவது external system உடன் synchronize செய்ய முயற்சிக்கவில்லை என்றால், உங்களுக்கு Effect தேவைப்படாமல் இருக்கலாம்.

  • Strict Mode on ஆக இருந்தால், முதல் real setup-க்கு முன் React development-only ஆன கூடுதல் setup+cleanup cycle ஒன்றை run செய்யும். உங்கள் cleanup logic, setup logic-ஐ “mirror” செய்கிறதா மற்றும் setup செய்கிறதை stop அல்லது undo செய்கிறதா என்பதை உறுதி செய்யும் stress-test இது. இது பிரச்சினை ஏற்படுத்தினால், cleanup function-ஐ implement செய்யுங்கள்.

  • உங்கள் dependencies-இல் சில objects அல்லது component-க்குள் defined ஆன functions இருந்தால், அவை தேவையானதை விட அதிகமாக Effect re-run ஆக காரணமாகும் அபாயம் உள்ளது. இதை fix செய்ய, தேவையற்ற object மற்றும் function dependencies-ஐ remove செய்யுங்கள். உங்கள் Effect-க்கு வெளியே state updates மற்றும் non-reactive logic-ஐயும் extract செய்யலாம்.

  • உங்கள் Effect interaction (click போன்றது) காரணமாக ஏற்பட்டதல்ல என்றால், React பொதுவாக browser-க்கு உங்கள் Effect run செய்வதற்கு முன் updated screen-ஐ முதலில் paint செய்ய அனுமதிக்கும். உங்கள் Effect visual ஏதாவது செய்கிறதானால் (உதாரணமாக tooltip position செய்தல்), delay கவனிக்கத்தக்கதாக இருந்தால் (உதாரணமாக flicker ஆனால்), useEffect-ஐ useLayoutEffect-ஆக மாற்றுங்கள்.

  • உங்கள் Effect interaction (click போன்றது) காரணமாக ஏற்பட்டிருந்தால், browser updated screen-ஐ paint செய்வதற்கு முன் React உங்கள் Effect-ஐ run செய்யலாம். Effect-ன் result-ஐ event system observe செய்ய முடியும் என்பதை இது உறுதி செய்கிறது. பொதுவாக இது எதிர்பார்த்தபடி வேலை செய்கிறது. ஆனால் alert() போன்ற work-ஐ paint-க்கு பிறகு வரை defer செய்ய வேண்டுமெனில், setTimeout use செய்யலாம். மேலும் தகவலுக்கு reactwg/react-18/128 பார்க்கவும்.

  • உங்கள் Effect interaction (click போன்றது) காரணமாக இருந்தாலும், உங்கள் Effect-க்குள் உள்ள state updates-ஐ process செய்வதற்கு முன் browser screen-ஐ repaint செய்ய React அனுமதிக்கலாம். பொதுவாக இது எதிர்பார்த்தபடி வேலை செய்கிறது. ஆனால் browser screen-ஐ repaint செய்வதை block செய்ய வேண்டுமெனில், useEffect-ஐ useLayoutEffect-ஆக மாற்ற வேண்டும்.

  • Effects client-இல் மட்டுமே run ஆகும். Server rendering போது அவை run ஆகாது.


Usage

External system-க்கு connect செய்தல்

சில components page-இல் display ஆகும் போது network, browser API, அல்லது third-party library ஒன்றுடன் connected ஆகவே இருக்க வேண்டும். இந்த systems React மூலம் controlled அல்ல; எனவே அவை external என்று அழைக்கப்படுகின்றன.

உங்கள் component-ஐ ஏதாவது external system-க்கு connect செய்ய, உங்கள் component-ன் top level-இல் useEffect call செய்யுங்கள்:

import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';

function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');

useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}

useEffect-க்கு இரண்டு arguments pass செய்ய வேண்டும்:

  1. அந்த system-க்கு connect செய்யும் setup code கொண்ட setup function.
    • அந்த system-இலிருந்து disconnect செய்யும் cleanup code கொண்ட cleanup function-ஐ அது return செய்ய வேண்டும்.
  2. அந்த functions-க்குள் use செய்யப்பட்ட உங்கள் component-இலிருந்து வரும் ஒவ்வொரு value-யையும் உள்ளடக்கும் dependencies list.

தேவைப்படும் ஒவ்வொரு முறையும் React உங்கள் setup மற்றும் cleanup functions-ஐ call செய்யும்; இது பல முறை நடக்கலாம்:

  1. உங்கள் component page-க்கு add செய்யப்படும் போது (mounts) உங்கள் setup code run ஆகும்.
  2. dependencies மாறிய உங்கள் component-ன் ஒவ்வொரு commit-க்கும் பிறகு:
    • முதலில், பழைய props மற்றும் state உடன் உங்கள் cleanup code run ஆகும்.
    • பின்னர், புதிய props மற்றும் state உடன் உங்கள் setup code run ஆகும்.
  3. உங்கள் component page-இலிருந்து remove செய்யப்பட்ட பிறகு (unmounts) உங்கள் cleanup code கடைசியாக ஒருமுறை run ஆகும்.

மேலுள்ள example-க்கு இந்த sequence-ஐ விளக்கிப் பார்ப்போம்.

மேலுள்ள ChatRoom component page-க்கு add செய்யப்படும் போது, அது initial serverUrl மற்றும் roomId உடன் chat room-க்கு connect ஆகும். Commit காரணமாக serverUrl அல்லது roomId ஏதாவது மாறினால் (உதாரணமாக user dropdown-இல் வேறு chat room தேர்வு செய்தால்), உங்கள் Effect முந்தைய room-இலிருந்து disconnect செய்து, அடுத்த room-க்கு connect ஆகும். ChatRoom component page-இலிருந்து remove செய்யப்படும் போது, உங்கள் Effect கடைசியாக ஒருமுறை disconnect செய்யும்.

Bugs கண்டுபிடிக்க உதவ, development-இல் React setup-க்கு முன் setup மற்றும் cleanup-ஐ கூடுதலாக ஒருமுறை run செய்கிறது. உங்கள் Effect-ன் logic சரியாக implemented உள்ளதா என்பதை verify செய்யும் stress-test இது. இது visible issues ஏற்படுத்தினால், உங்கள் cleanup function-இல் சில logic missing. Cleanup function setup function செய்ததை stop அல்லது undo செய்ய வேண்டும். Rule of thumb: setup ஒருமுறை call செய்யப்படுவது (production போல) மற்றும் setupcleanupsetup sequence (development போல) இடையே user வேறுபாடு காணக்கூடாது. பொதுவான solutions பார்க்கவும்.

ஒவ்வொரு Effect-ஐயும் independent process ஆக எழுத முயற்சிக்கவும்; மேலும் ஒரு setup/cleanup cycle பற்றி மட்டும் ஒரே நேரத்தில் சிந்திக்கவும். உங்கள் component mounting, updating, அல்லது unmounting ஆகியவற்றில் எது நடக்கிறது என்பது முக்கியமாக இருக்கக்கூடாது. Cleanup logic setup logic-ஐ சரியாக “mirror” செய்தால், setup மற்றும் cleanup தேவையான அளவு அடிக்கடி run ஆனாலும் உங்கள் Effect resilient ஆக இருக்கும்.

Note

Effect ஒன்று உங்கள் component-ஐ chat service போன்ற external system உடன் synchronized ஆக வைத்திருக்க அனுமதிக்கிறது. இங்கே external system என்பது React மூலம் controlled அல்லாத எந்த code பகுதியையும் குறிக்கும், உதாரணமாக:

நீங்கள் எந்த external system-க்கும் connect செய்யவில்லை என்றால், உங்களுக்கு Effect தேவைப்படாமல் இருக்கலாம்.

External system-க்கு connect செய்வதற்கான examples

Example 1 of 5:
Chat server-க்கு connect செய்தல்

இந்த example-இல், ChatRoom component chat.js-இல் defined செய்யப்பட்ட external system உடன் connected ஆக இருக்க Effect use செய்கிறது. ChatRoom component தோன்ற “Chat-ஐ திற” அழுத்துங்கள். இந்த sandbox development mode-இல் run ஆகிறது; எனவே இங்கே விளக்கப்பட்டுள்ளபடி கூடுதல் connect-and-disconnect cycle ஒன்று உள்ளது. Dropdown மற்றும் input பயன்படுத்தி roomId மற்றும் serverUrl மாற்றிப் பார்த்து, Effect chat-க்கு எப்படி re-connect ஆகிறது என்பதை பாருங்கள். Effect கடைசியாக ஒருமுறை disconnect ஆகுவதைக் காண “Chat-ஐ மூடு” அழுத்துங்கள்.

import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';

function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:1234');

  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.connect();
    return () => {
      connection.disconnect();
    };
  }, [roomId, serverUrl]);

  return (
    <>
      <label>
        Server URL:{' '}
        <input
          value={serverUrl}
          onChange={e => setServerUrl(e.target.value)}
        />
      </label>
      <h1>{roomId} அறைக்கு வரவேற்கிறோம்!</h1>
    </>
  );
}

export default function App() {
  const [roomId, setRoomId] = useState('general');
  const [show, setShow] = useState(false);
  return (
    <>
      <label>
        Chat room-ஐ தேர்வு செய்க:{' '}
        <select
          value={roomId}
          onChange={e => setRoomId(e.target.value)}
        >
          <option value="general">பொது</option>
          <option value="travel">பயணம்</option>
          <option value="music">இசை</option>
        </select>
      </label>
      <button onClick={() => setShow(!show)}>
        {show ? 'Chat-ஐ மூடு' : 'Chat-ஐ திற'}
      </button>
      {show && <hr />}
      {show && <ChatRoom roomId={roomId} />}
    </>
  );
}


Effects-ஐ custom Hooks-இல் wrap செய்தல்

Effects ஒரு “escape hatch”: நீங்கள் “React-க்கு வெளியே step செய்ய” வேண்டியபோது மற்றும் உங்கள் use case-க்கு சிறந்த built-in solution இல்லாதபோது அவற்றை use செய்கிறீர்கள். Effects-ஐ அடிக்கடி manual ஆக எழுத வேண்டிய நிலை உங்களுக்கு வந்தால், உங்கள் components சார்ந்திருக்கும் common behaviors-க்கு சில custom Hooks extract செய்ய வேண்டும் என்பதற்கான அறிகுறியாக அது இருக்கும்.

உதாரணமாக, இந்த useChatRoom custom Hook உங்கள் Effect-ன் logic-ஐ இன்னும் declarative API பின்னால் “hide” செய்கிறது:

function useChatRoom({ serverUrl, roomId }) {
useEffect(() => {
const options = {
serverUrl: serverUrl,
roomId: roomId
};
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [roomId, serverUrl]);
}

பிறகு எந்த component-இலிருந்தும் அதை இவ்வாறு use செய்யலாம்:

function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');

useChatRoom({
roomId: roomId,
serverUrl: serverUrl
});
// ...

React ecosystem-இல் ஒவ்வொரு purpose-க்கும் பல சிறந்த custom Hooks கிடைக்கின்றன.

Effects-ஐ custom Hooks-இல் wrap செய்வது பற்றி மேலும் அறிக.

Effects-ஐ custom Hooks-இல் wrap செய்வதற்கான examples

Example 1 of 3:
Custom useChatRoom Hook

இந்த example முந்தைய examples-இல் ஒன்றுக்கு identical; ஆனால் logic custom Hook-க்கு extract செய்யப்பட்டுள்ளது.

import { useState } from 'react';
import { useChatRoom } from './useChatRoom.js';

function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:1234');

  useChatRoom({
    roomId: roomId,
    serverUrl: serverUrl
  });

  return (
    <>
      <label>
        Server URL:{' '}
        <input
          value={serverUrl}
          onChange={e => setServerUrl(e.target.value)}
        />
      </label>
      <h1>{roomId} அறைக்கு வரவேற்கிறோம்!</h1>
    </>
  );
}

export default function App() {
  const [roomId, setRoomId] = useState('general');
  const [show, setShow] = useState(false);
  return (
    <>
      <label>
        Chat room-ஐ தேர்வு செய்க:{' '}
        <select
          value={roomId}
          onChange={e => setRoomId(e.target.value)}
        >
          <option value="general">பொது</option>
          <option value="travel">பயணம்</option>
          <option value="music">இசை</option>
        </select>
      </label>
      <button onClick={() => setShow(!show)}>
        {show ? 'Chat-ஐ மூடு' : 'Chat-ஐ திற'}
      </button>
      {show && <hr />}
      {show && <ChatRoom roomId={roomId} />}
    </>
  );
}


Non-React widget-ஐ control செய்தல்

சில நேரங்களில், external system ஒன்றை உங்கள் component-ன் prop அல்லது state ஒன்றுடன் synchronized ஆக வைத்திருக்க விரும்புவீர்கள்.

உதாரணமாக, React இல்லாமல் எழுதப்பட்ட third-party map widget அல்லது video player component உங்களிடம் இருந்தால், அதன் state உங்கள் React component-ன் current state-க்கு match ஆகும் வகையில் அதில் methods call செய்ய Effect use செய்யலாம். இந்த Effect map-widget.js-இல் defined செய்யப்பட்ட MapWidget class-ன் instance ஒன்றை create செய்கிறது. Map component-ன் zoomLevel prop-ஐ மாற்றும்போது, அதை synchronized ஆக வைத்திருக்க Effect class instance-இல் setZoom() call செய்கிறது:

import { useRef, useEffect } from 'react';
import { MapWidget } from './map-widget.js';

export default function Map({ zoomLevel }) {
  const containerRef = useRef(null);
  const mapRef = useRef(null);

  useEffect(() => {
    if (mapRef.current === null) {
      mapRef.current = new MapWidget(containerRef.current);
    }

    const map = mapRef.current;
    map.setZoom(zoomLevel);
  }, [zoomLevel]);

  return (
    <div
      style={{ width: 200, height: 200 }}
      ref={containerRef}
    />
  );
}

இந்த example-இல் cleanup function தேவையில்லை; ஏனெனில் MapWidget class அதற்கு pass செய்யப்பட்ட DOM node-ஐ மட்டும் manage செய்கிறது. Map React component tree-இலிருந்து remove செய்யப்பட்ட பிறகு, DOM node மற்றும் MapWidget class instance இரண்டும் browser JavaScript engine மூலம் automatic ஆக garbage-collected ஆகும்.


Effects மூலம் data fetch செய்தல்

உங்கள் component-க்காக data fetch செய்ய Effect use செய்யலாம். நீங்கள் framework use செய்தால், Effects-ஐ manual ஆக எழுதுவதைக் காட்டிலும் உங்கள் framework-ன் data fetching mechanism use செய்வது மிகவும் efficient ஆக இருக்கும் என்பதை கவனிக்கவும்.

Effect-இலிருந்து data-ஐ manual ஆக fetch செய்ய விரும்பினால், உங்கள் code இவ்வாறு இருக்கலாம்:

import { useState, useEffect } from 'react';
import { fetchBio } from './api.js';

export default function Page() {
const [person, setPerson] = useState('Alice');
const [bio, setBio] = useState(null);

useEffect(() => {
let ignore = false;
setBio(null);
fetchBio(person).then(result => {
if (!ignore) {
setBio(result);
}
});
return () => {
ignore = true;
};
}, [person]);

// ...

false ஆக initialized செய்யப்பட்டு cleanup போது true ஆக set செய்யப்படும் ignore variable-ஐ கவனியுங்கள். Network responses நீங்கள் அனுப்பிய order-இல் அல்லாமல் வேறு order-இல் வரக்கூடும்; உங்கள் code “race conditions” காரணமாக பாதிக்கப்படாமல் இருப்பதை இது உறுதி செய்கிறது.

import { useState, useEffect } from 'react';
import { fetchBio } from './api.js';

export default function Page() {
  const [person, setPerson] = useState('Alice');
  const [bio, setBio] = useState(null);
  useEffect(() => {
    let ignore = false;
    setBio(null);
    fetchBio(person).then(result => {
      if (!ignore) {
        setBio(result);
      }
    });
    return () => {
      ignore = true;
    }
  }, [person]);

  return (
    <>
      <select value={person} onChange={e => {
        setPerson(e.target.value);
      }}>
        <option value="Alice">Alice</option>
        <option value="Bob">Bob</option>
        <option value="Taylor">Taylor</option>
      </select>
      <hr />
      <p><i>{bio ?? 'ஏற்றுகிறது...'}</i></p>
    </>
  );
}

async / await syntax பயன்படுத்தியும் rewrite செய்யலாம்; ஆனால் cleanup function இன்னும் provide செய்ய வேண்டும்:

import { useState, useEffect } from 'react';
import { fetchBio } from './api.js';

export default function Page() {
  const [person, setPerson] = useState('Alice');
  const [bio, setBio] = useState(null);
  useEffect(() => {
    async function startFetching() {
      setBio(null);
      const result = await fetchBio(person);
      if (!ignore) {
        setBio(result);
      }
    }

    let ignore = false;
    startFetching();
    return () => {
      ignore = true;
    }
  }, [person]);

  return (
    <>
      <select value={person} onChange={e => {
        setPerson(e.target.value);
      }}>
        <option value="Alice">Alice</option>
        <option value="Bob">Bob</option>
        <option value="Taylor">Taylor</option>
      </select>
      <hr />
      <p><i>{bio ?? 'ஏற்றுகிறது...'}</i></p>
    </>
  );
}

Data fetching-ஐ நேரடியாக Effects-இல் எழுதுவது repetitive ஆகும்; பின்னர் caching மற்றும் server rendering போன்ற optimizations சேர்ப்பதையும் கடினமாக்கும். உங்கள் சொந்த custom Hook-ஆக இருந்தாலும் அல்லது community maintained Hook-ஆக இருந்தாலும் அதை use செய்வது மேம்படும்.

Deep Dive

Effects-இல் data fetching-க்கு நல்ல alternatives என்ன?

Effects-க்குள் fetch calls எழுதுவது, குறிப்பாக முழுமையாக client-side apps-இல், data fetch செய்வதற்கான popular வழி. ஆனால் இது மிகவும் manual approach; மேலும் குறிப்பிடத்தக்க downsides உள்ளன:

  • Effects server-இல் run ஆகாது. இதன் பொருள் initial server-rendered HTML data இல்லாத loading state மட்டும் கொண்டிருக்கும். Client computer எல்லா JavaScript-ஐயும் download செய்து app-ஐ render செய்த பிறகே இப்போது data load செய்ய வேண்டும் என்பதை கண்டறியும். இது efficient அல்ல.
  • Effects-இல் நேரடியாக fetching செய்வது “network waterfalls” உருவாக்க உதவுகிறது. நீங்கள் parent component-ஐ render செய்கிறீர்கள்; அது சில data fetch செய்கிறது; child components-ஐ render செய்கிறது; பின்னர் அவை தங்கள் data fetch செய்ய தொடங்குகின்றன. Network வேகமாக இல்லையெனில், எல்லா data-யையும் parallel-ஆக fetch செய்வதை விட இது குறிப்பிடத்தக்க அளவு slow.
  • Effects-இல் நேரடியாக fetching செய்வது பொதுவாக data preload அல்லது cache செய்யப்படாது என்பதைக் குறிக்கும். உதாரணமாக, component unmount ஆகி மீண்டும் mount ஆனால், data-ஐ மீண்டும் fetch செய்ய வேண்டியிருக்கும்.
  • இது மிகவும் ergonomic அல்ல. Race conditions போன்ற bugs ஏற்படாத வகையில் fetch calls எழுதும்போது கணிசமான boilerplate code தேவைப்படும்.

இந்த downsides list React-க்கு மட்டும் குறிப்பானது அல்ல. எந்த library-யுடனும் mount போது data fetch செய்வதற்கு இது பொருந்தும். Routing போலவே, data fetching-ஐ நன்றாக செய்வது trivial அல்ல; எனவே பின்வரும் approaches-ஐ பரிந்துரைக்கிறோம்:

  • நீங்கள் framework use செய்தால், அதன் built-in data fetching mechanism-ஐ use செய்யுங்கள். Modern React frameworks efficient ஆன, மேலுள்ள pitfalls இல்லாத integrated data fetching mechanisms கொண்டுள்ளன.
  • இல்லையெனில், client-side cache use செய்வதையோ build செய்வதையோ consider செய்யுங்கள். Popular open source solutions-இல் TanStack Query, useSWR, மற்றும் React Router 6.4+ அடங்கும். உங்கள் சொந்த solution-ஐயும் build செய்யலாம்; அப்போது under the hood Effects use செய்வீர்கள், ஆனால் requests-ஐ deduplicate செய்தல், responses-ஐ cache செய்தல், மற்றும் network waterfalls தவிர்த்தல் (data preload செய்வதன் மூலம் அல்லது data requirements-ஐ routes-க்கு hoist செய்வதன் மூலம்) ஆகிய logic சேர்ப்பீர்கள்.

இந்த approaches எதுவும் உங்களுக்கு பொருந்தவில்லை என்றால், Effects-இல் நேரடியாக data fetch செய்வதைத் தொடரலாம்.


Reactive dependencies specify செய்தல்

உங்கள் Effect-ன் dependencies-ஐ நீங்கள் “தேர்வு” செய்ய முடியாது என்பதை கவனியுங்கள். உங்கள் Effect code use செய்யும் ஒவ்வொரு reactive value-உம் dependency ஆக declare செய்யப்பட வேண்டும். உங்கள் Effect-ன் dependency list surrounding code மூலம் determined ஆகிறது:

function ChatRoom({ roomId }) { // இது reactive value
const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // இதுவும் reactive value

useEffect(() => {
const connection = createConnection(serverUrl, roomId); // இந்த Effect இந்த reactive values-ஐ read செய்கிறது
connection.connect();
return () => connection.disconnect();
}, [serverUrl, roomId]); // ✅ எனவே அவற்றை உங்கள் Effect-ன் dependencies ஆக specify செய்ய வேண்டும்
// ...
}

serverUrl அல்லது roomId ஏதாவது மாறினால், உங்கள் Effect புதிய values பயன்படுத்தி chat-க்கு reconnect செய்யும்.

Reactive values-இல் props மற்றும் உங்கள் component-க்குள் நேரடியாக declared செய்யப்பட்ட அனைத்து variables மற்றும் functions அடங்கும். roomId மற்றும் serverUrl reactive values என்பதால், அவற்றை dependencies-இலிருந்து remove செய்ய முடியாது. அவற்றை omit செய்ய முயற்சித்து உங்கள் linter React-க்காக சரியாக configured செய்யப்பட்டிருந்தால், இதை fix செய்ய வேண்டிய தவறாக linter flag செய்யும்:

function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');

useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, []); // 🔴 React Hook useEffect-க்கு missing dependencies உள்ளன: 'roomId' மற்றும் 'serverUrl'
// ...
}

Dependency ஒன்றை remove செய்ய, அது dependency ஆக இருக்க தேவையில்லை என்பதை linter-க்கு “prove” செய்ய வேண்டும். உதாரணமாக, serverUrl reactive அல்ல மற்றும் re-renders போது மாறாது என்பதை prove செய்ய, அதை உங்கள் component-க்கு வெளியே move செய்யலாம்:

const serverUrl = 'https://localhost:1234'; // இனி reactive value அல்ல

function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]); // ✅ எல்லா dependencies-உம் declared
// ...
}

இப்போது serverUrl reactive value அல்ல (மற்றும் re-render போது மாற முடியாது), அது dependency ஆக இருக்க தேவையில்லை. உங்கள் Effect code எந்த reactive values-யும் use செய்யவில்லை என்றால், அதன் dependency list empty ([]) ஆக இருக்க வேண்டும்:

const serverUrl = 'https://localhost:1234'; // இனி reactive value அல்ல
const roomId = 'music'; // இனி reactive value அல்ல

function ChatRoom() {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, []); // ✅ எல்லா dependencies-உம் declared
// ...
}

Empty dependencies கொண்ட Effect உங்கள் component-ன் props அல்லது state ஏதாவது மாறும்போது re-run ஆகாது.

Pitfall

உங்களிடம் existing codebase இருந்தால், linter-ஐ இவ்வாறு suppress செய்யும் சில Effects இருக்கலாம்:

useEffect(() => {
// ...
// 🔴 Avoid suppressing the linter like this:
// eslint-ignore-next-line react-hooks/exhaustive-deps
}, []);

Dependencies code-க்கு match ஆகவில்லை என்றால், bugs அறிமுகப்படுத்தும் risk அதிகம். Linter-ஐ suppress செய்வதன் மூலம், உங்கள் Effect depend செய்யும் values பற்றி React-க்கு நீங்கள் “பொய்” சொல்கிறீர்கள். அதற்கு பதிலாக, அவை தேவையற்றவை என்பதை prove செய்யுங்கள்.

Reactive dependencies pass செய்வதற்கான examples

Example 1 of 3:
Dependency array pass செய்தல்

Dependencies-ஐ specify செய்தால், உங்கள் Effect initial commit-க்கு பிறகும் மற்றும் dependencies மாறிய commits-க்கு பிறகும் run ஆகும்.

useEffect(() => {
// ...
}, [a, b]); // a அல்லது b வேறுபட்டால் மீண்டும் run ஆகும்

கீழுள்ள example-இல், serverUrl மற்றும் roomId reactive values; எனவே இரண்டும் dependencies ஆக specify செய்யப்பட வேண்டும். அதன் விளைவாக, dropdown-இல் வேறு room தேர்வு செய்தாலும் அல்லது server URL input edit செய்தாலும் chat re-connect ஆகும். ஆனால் message Effect-இல் use செய்யப்படாததால் (அதனால் dependency அல்ல), message edit செய்தால் chat re-connect ஆகாது.

import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';

function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:1234');
  const [message, setMessage] = useState('');

  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.connect();
    return () => {
      connection.disconnect();
    };
  }, [serverUrl, roomId]);

  return (
    <>
      <label>
        Server URL:{' '}
        <input
          value={serverUrl}
          onChange={e => setServerUrl(e.target.value)}
        />
      </label>
      <h1>{roomId} அறைக்கு வரவேற்கிறோம்!</h1>
      <label>
        உங்கள் message:{' '}
        <input value={message} onChange={e => setMessage(e.target.value)} />
      </label>
    </>
  );
}

export default function App() {
  const [show, setShow] = useState(false);
  const [roomId, setRoomId] = useState('general');
  return (
    <>
      <label>
        Chat room-ஐ தேர்வு செய்க:{' '}
        <select
          value={roomId}
          onChange={e => setRoomId(e.target.value)}
        >
          <option value="general">பொது</option>
          <option value="travel">பயணம்</option>
          <option value="music">இசை</option>
        </select>
        <button onClick={() => setShow(!show)}>
          {show ? 'Chat-ஐ மூடு' : 'Chat-ஐ திற'}
        </button>
      </label>
      {show && <hr />}
      {show && <ChatRoom roomId={roomId}/>}
    </>
  );
}


Effect-இலிருந்து previous state அடிப்படையில் state update செய்தல்

Effect-இலிருந்து previous state அடிப்படையில் state update செய்ய விரும்பும்போது, ஒரு பிரச்சினை வரலாம்:

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

useEffect(() => {
const intervalId = setInterval(() => {
setCount(count + 1); // Counter-ஐ ஒவ்வொரு second-க்கும் increment செய்ய விரும்புகிறீர்கள்...
}, 1000)
return () => clearInterval(intervalId);
}, [count]); // 🚩 ...ஆனால் `count`-ஐ dependency ஆக specify செய்தால் interval எப்போதும் reset ஆகும்.
// ...
}

count reactive value என்பதால், அது dependencies list-இல் specify செய்யப்பட வேண்டும். ஆனால் count மாறும் ஒவ்வொரு முறையும் Effect cleanup செய்து மீண்டும் setup செய்ய இது காரணமாகிறது. இது ideal அல்ல.

இதை fix செய்ய, setCount-க்கு c => c + 1 state updater-ஐ pass செய்யுங்கள்:

import { useState, useEffect } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const intervalId = setInterval(() => {
      setCount(c => c + 1); // ✅ State updater-ஐ pass செய்க
    }, 1000);
    return () => clearInterval(intervalId);
  }, []); // ✅ இப்போது count dependency அல்ல

  return <h1>{count}</h1>;
}

இப்போது count + 1 பதிலாக c => c + 1 pass செய்வதால், உங்கள் Effect இனி count-ஐ depend செய்ய வேண்டியதில்லை. இந்த fix-ன் விளைவாக, count மாறும் ஒவ்வொரு முறையும் interval-ஐ cleanup செய்து setup செய்ய தேவையில்லை.


தேவையற்ற object dependencies-ஐ நீக்குதல்

உங்கள் Effect rendering போது create செய்யப்பட்ட object அல்லது function ஒன்றை depend செய்தால், அது மிக அடிக்கடி run ஆகலாம். உதாரணமாக, options object ஒவ்வொரு render-க்கும் வேறுபடுவதால் இந்த Effect ஒவ்வொரு commit-க்கும் பிறகு re-connect ஆகிறது:

const serverUrl = 'https://localhost:1234';

function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');

const options = { // 🚩 இந்த object ஒவ்வொரு re-render-க்கும் scratch-இலிருந்து create செய்யப்படுகிறது
serverUrl: serverUrl,
roomId: roomId
};

useEffect(() => {
const connection = createConnection(options); // இது Effect-க்குள் use செய்யப்படுகிறது
connection.connect();
return () => connection.disconnect();
}, [options]); // 🚩 அதன் விளைவாக, இந்த dependencies ஒவ்வொரு commit-இலும் எப்போதும் வேறுபடும்
// ...

Rendering போது create செய்யப்பட்ட object-ஐ dependency ஆக use செய்வதை தவிர்க்கவும். அதற்கு பதிலாக, object-ஐ Effect-க்குள் create செய்யுங்கள்:

import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';

const serverUrl = 'https://localhost:1234';

function ChatRoom({ roomId }) {
  const [message, setMessage] = useState('');

  useEffect(() => {
    const options = {
      serverUrl: serverUrl,
      roomId: roomId
    };
    const connection = createConnection(options);
    connection.connect();
    return () => connection.disconnect();
  }, [roomId]);

  return (
    <>
      <h1>{roomId} அறைக்கு வரவேற்கிறோம்!</h1>
      <input value={message} onChange={e => setMessage(e.target.value)} />
    </>
  );
}

export default function App() {
  const [roomId, setRoomId] = useState('general');
  return (
    <>
      <label>
        Chat room-ஐ தேர்வு செய்க:{' '}
        <select
          value={roomId}
          onChange={e => setRoomId(e.target.value)}
        >
          <option value="general">பொது</option>
          <option value="travel">பயணம்</option>
          <option value="music">இசை</option>
        </select>
      </label>
      <hr />
      <ChatRoom roomId={roomId} />
    </>
  );
}

இப்போது options object-ஐ Effect-க்குள் create செய்வதால், Effect தானாகவே roomId string-ஐ மட்டும் depend செய்கிறது.

இந்த fix உடன், input-இல் type செய்வது chat-ஐ reconnect செய்யாது. Re-created ஆகும் object போல அல்லாமல், roomId போன்ற string-ஐ வேறு value-ஆக set செய்யாவிட்டால் அது மாறாது. Dependencies remove செய்வது பற்றி மேலும் படிக்கவும்.


தேவையற்ற function dependencies-ஐ நீக்குதல்

உங்கள் Effect rendering போது create செய்யப்பட்ட object அல்லது function ஒன்றை depend செய்தால், அது மிக அடிக்கடி run ஆகலாம். உதாரணமாக, createOptions function ஒவ்வொரு render-க்கும் வேறுபடுவதால் இந்த Effect ஒவ்வொரு commit-க்கும் பிறகு re-connect ஆகிறது:

function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');

function createOptions() { // 🚩 இந்த function ஒவ்வொரு re-render-க்கும் scratch-இலிருந்து create செய்யப்படுகிறது
return {
serverUrl: serverUrl,
roomId: roomId
};
}

useEffect(() => {
const options = createOptions(); // இது Effect-க்குள் use செய்யப்படுகிறது
const connection = createConnection();
connection.connect();
return () => connection.disconnect();
}, [createOptions]); // 🚩 அதன் விளைவாக, இந்த dependencies ஒவ்வொரு commit-இலும் எப்போதும் வேறுபடும்
// ...

ஒவ்வொரு re-render-க்கும் function ஒன்றை scratch-இலிருந்து create செய்வது தனியாக ஒரு problem அல்ல. அதை optimize செய்ய தேவையில்லை. ஆனால் அதை உங்கள் Effect-ன் dependency ஆக use செய்தால், அது ஒவ்வொரு commit-க்கும் பிறகு உங்கள் Effect re-run ஆக காரணமாகும்.

Rendering போது create செய்யப்பட்ட function-ஐ dependency ஆக use செய்வதை தவிர்க்கவும். அதற்கு பதிலாக, அதை Effect-க்குள் declare செய்யுங்கள்:

import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';

const serverUrl = 'https://localhost:1234';

function ChatRoom({ roomId }) {
  const [message, setMessage] = useState('');

  useEffect(() => {
    function createOptions() {
      return {
        serverUrl: serverUrl,
        roomId: roomId
      };
    }

    const options = createOptions();
    const connection = createConnection(options);
    connection.connect();
    return () => connection.disconnect();
  }, [roomId]);

  return (
    <>
      <h1>{roomId} அறைக்கு வரவேற்கிறோம்!</h1>
      <input value={message} onChange={e => setMessage(e.target.value)} />
    </>
  );
}

export default function App() {
  const [roomId, setRoomId] = useState('general');
  return (
    <>
      <label>
        Chat room-ஐ தேர்வு செய்க:{' '}
        <select
          value={roomId}
          onChange={e => setRoomId(e.target.value)}
        >
          <option value="general">பொது</option>
          <option value="travel">பயணம்</option>
          <option value="music">இசை</option>
        </select>
      </label>
      <hr />
      <ChatRoom roomId={roomId} />
    </>
  );
}

இப்போது createOptions function-ஐ Effect-க்குள் define செய்வதால், Effect தானாகவே roomId string-ஐ மட்டும் depend செய்கிறது. இந்த fix உடன், input-இல் type செய்வது chat-ஐ reconnect செய்யாது. Re-created ஆகும் function போல அல்லாமல், roomId போன்ற string-ஐ வேறு value-ஆக set செய்யாவிட்டால் அது மாறாது. Dependencies remove செய்வது பற்றி மேலும் படிக்கவும்.


Effect-இலிருந்து latest props மற்றும் state படித்தல்

Default ஆக, Effect-இலிருந்து reactive value ஒன்றை read செய்தால், அதை dependency ஆக add செய்ய வேண்டும். அந்த value-ன் ஒவ்வொரு change-க்கும் உங்கள் Effect “react” செய்யும் என்பதை இது உறுதி செய்கிறது. பெரும்பாலான dependencies-க்கு, இதுவே நீங்கள் விரும்பும் behavior.

ஆனால் சில நேரங்களில், அவற்றுக்கு “react” செய்யாமல் Effect-இலிருந்து latest props மற்றும் state-ஐ read செய்ய நீங்கள் விரும்புவீர்கள். உதாரணமாக, ஒவ்வொரு page visit-க்கும் shopping cart-இல் உள்ள items எண்ணிக்கையை log செய்ய விரும்புகிறீர்கள் என்று கற்பனை செய்யுங்கள்:

function Page({ url, shoppingCart }) {
useEffect(() => {
logVisit(url, shoppingCart.length);
}, [url, shoppingCart]); // ✅ எல்லா dependencies-உம் declared
// ...
}

ஒவ்வொரு url change-க்கும் பிறகு புதிய page visit log செய்ய வேண்டும், ஆனால் shoppingCart மட்டும் மாறினால் வேண்டாம் என்றால்? Reactivity rules-ஐ break செய்யாமல் shoppingCart-ஐ dependencies-இலிருந்து exclude செய்ய முடியாது. ஆனால் Effect-க்குள் இருந்து call செய்யப்பட்டாலும், code-ன் ஒரு பகுதி changes-க்கு “react” செய்ய வேண்டாம் என்று express செய்யலாம். useEffectEvent Hook மூலம் Effect Event declare செய்து, shoppingCart read செய்யும் code-ஐ அதற்குள் move செய்யுங்கள்:

function Page({ url, shoppingCart }) {
const onVisit = useEffectEvent(visitedUrl => {
logVisit(visitedUrl, shoppingCart.length)
});

useEffect(() => {
onVisit(url);
}, [url]); // ✅ எல்லா dependencies-உம் declared
// ...
}

Effect Events reactive அல்ல; அவை உங்கள் Effect-ன் dependencies-இலிருந்து எப்போதும் omit செய்யப்பட வேண்டும். இதுவே non-reactive code-ஐ (சில props மற்றும் state-ன் latest value-ஐ read செய்யும் இடம்) அவற்றுக்குள் வைக்க அனுமதிக்கிறது. onVisit-க்குள் shoppingCart read செய்வதன் மூலம், shoppingCart உங்கள் Effect-ஐ re-run செய்யாது என்பதை உறுதி செய்கிறீர்கள்.

Effect Events reactive மற்றும் non-reactive code-ஐ பிரிக்க எப்படி உதவுகின்றன என்பதை மேலும் படிக்கவும்.


Server மற்றும் client-இல் வேறுபட்ட content display செய்தல்

உங்கள் app server rendering use செய்தால் (நேரடியாக அல்லது framework மூலம்), உங்கள் component இரண்டு வேறுபட்ட environments-இல் render ஆகும். Server-இல், initial HTML produce செய்ய அது render ஆகும். Client-இல், அந்த HTML-க்கு உங்கள் event handlers attach செய்ய React rendering code-ஐ மீண்டும் run செய்யும். அதனால்தான் hydration வேலை செய்ய, உங்கள் initial render output client மற்றும் server-இல் identical ஆக இருக்க வேண்டும்.

அரிதான cases-இல், client-இல் வேறுபட்ட content display செய்ய வேண்டியிருக்கலாம். உதாரணமாக, உங்கள் app localStorage-இலிருந்து சில data read செய்தால், server-இல் அதை செய்ய முடியாது. இதை இவ்வாறு implement செய்யலாம்:

function MyComponent() {
const [didMount, setDidMount] = useState(false);

useEffect(() => {
setDidMount(true);
}, []);

if (didMount) {
// ... return client-only JSX ...
} else {
// ... return initial JSX ...
}
}

App loading ஆகும் போது, user initial render output-ஐ பார்ப்பார். பின்னர் அது loaded மற்றும் hydrated ஆனதும், உங்கள் Effect run ஆகி didMount-ஐ true ஆக set செய்து re-render trigger செய்யும். இது client-only render output-க்கு switch செய்யும். Effects server-இல் run ஆகாததால், initial server render போது didMount false ஆக இருந்தது இதனால்தான்.

இந்த pattern-ஐ குறைவாக use செய்யுங்கள். Slow connection கொண்ட users initial content-ஐ கணிசமான நேரம்—சில seconds கூட—பார்ப்பார்கள் என்பதை நினைவில் கொள்ளுங்கள்; எனவே உங்கள் component appearance-இல் jarring changes செய்ய விரும்பமாட்டீர்கள். பல cases-இல், CSS மூலம் conditionally வேறுபட்ட விஷயங்களை காட்டி இதற்கான தேவையை தவிர்க்கலாம்.


Troubleshooting

Component mount ஆகும்போது என் Effect இருமுறை run ஆகிறது

Strict Mode on ஆக இருந்தால், development-இல் actual setup-க்கு முன் React setup மற்றும் cleanup-ஐ கூடுதலாக ஒருமுறை run செய்கிறது.

உங்கள் Effect-ன் logic சரியாக implemented உள்ளதா என்பதை verify செய்யும் stress-test இது. இது visible issues ஏற்படுத்தினால், உங்கள் cleanup function-இல் சில logic missing. Cleanup function setup function செய்ததை stop அல்லது undo செய்ய வேண்டும். Rule of thumb: setup ஒருமுறை call செய்யப்படுவது (production போல) மற்றும் setup → cleanup → setup sequence (development போல) இடையே user வேறுபாடு காணக்கூடாது.

இது bugs கண்டுபிடிக்க எப்படி உதவுகிறது மற்றும் உங்கள் logic-ஐ எப்படி fix செய்வது பற்றி மேலும் படிக்கவும்.


ஒவ்வொரு re-render-க்கும் பிறகு என் Effect run ஆகிறது

முதலில், dependency array specify செய்ய மறந்துவிடவில்லை என்பதை check செய்யுங்கள்:

useEffect(() => {
// ...
}); // 🚩 Dependency array இல்லை: ஒவ்வொரு commit-க்கும் பிறகு re-run ஆகும்!

Dependency array specify செய்திருந்தும் உங்கள் Effect loop-இல் re-run ஆகிக் கொண்டிருந்தால், உங்கள் dependencies-இல் ஒன்று ஒவ்வொரு re-render-க்கும் வேறுபடுவதால்தான்.

உங்கள் dependencies-ஐ console-க்கு manual ஆக log செய்து இந்த problem-ஐ debug செய்யலாம்:

useEffect(() => {
// ..
}, [serverUrl, roomId]);

console.log([serverUrl, roomId]);

பின்னர் console-இல் வேறுபட்ட re-renders-இலிருந்து வந்த arrays-ஐ right-click செய்து இரண்டிற்கும் “Store as a global variable” select செய்யலாம். முதல் ஒன்று temp1 ஆகவும் இரண்டாவது ஒன்று temp2 ஆகவும் save ஆனதாகக் கொண்டு, இரு arrays-இலுள்ள ஒவ்வொரு dependency-யும் same ஆக உள்ளதா என்பதை browser console மூலம் check செய்யலாம்:

Object.is(temp1[0], temp2[0]); // arrays இடையே முதல் dependency same ஆக உள்ளதா?
Object.is(temp1[1], temp2[1]); // arrays இடையே இரண்டாவது dependency same ஆக உள்ளதா?
Object.is(temp1[2], temp2[2]); // ... ஒவ்வொரு dependency-க்கும் இதேபோல் ...

ஒவ்வொரு re-render-க்கும் வேறுபடும் dependency-ஐ கண்டுபிடித்ததும், பொதுவாக பின்வரும் வழிகளில் ஒன்றால் அதை fix செய்யலாம்:

Last resort ஆக (இந்த methods உதவவில்லை என்றால்), அதன் creation-ஐ useMemo அல்லது (functions-க்கு) useCallback மூலம் wrap செய்யுங்கள்.


என் Effect infinite cycle-இல் தொடர்ந்து re-run ஆகிறது

உங்கள் Effect infinite cycle-இல் run ஆனால், இந்த இரண்டு விஷயங்களும் உண்மை ஆக வேண்டும்:

  • உங்கள் Effect ஏதாவது state-ஐ update செய்கிறது.
  • அந்த state re-render-க்கு வழிவகுக்கிறது; அது Effect-ன் dependencies மாற காரணமாகிறது.

Problem-ஐ fix செய்யத் தொடங்குவதற்கு முன், உங்கள் Effect DOM, network, third-party widget போன்ற external system ஒன்றுடன் connect செய்கிறதா என்று உங்களையே கேளுங்கள். உங்கள் Effect ஏன் state set செய்ய வேண்டும்? அது அந்த external system உடன் synchronize செய்கிறதா? அல்லது உங்கள் application’s data flow-ஐ அதன்மூலம் manage செய்ய முயற்சிக்கிறீர்களா?

External system இல்லையெனில், Effect-ஐ முழுமையாக remove செய்வது உங்கள் logic-ஐ simplify செய்யுமா என்று consider செய்யுங்கள்.

நீங்கள் உண்மையாக external system ஒன்றுடன் synchronize செய்கிறீர்கள் என்றால், உங்கள் Effect ஏன் மற்றும் எந்த conditions-இல் state update செய்ய வேண்டும் என்று சிந்தியுங்கள். உங்கள் component-ன் visual output-ஐ பாதிக்கும் ஏதாவது மாறியுள்ளதா? Rendering-இல் use செய்யப்படாத data ஒன்றை track செய்ய வேண்டுமெனில், re-renders trigger செய்யாத ref இன்னும் பொருத்தமாக இருக்கலாம். உங்கள் Effect தேவையானதை விட அதிகமாக state update செய்து re-renders trigger செய்யவில்லை என்பதை verify செய்யுங்கள்.

இறுதியாக, உங்கள் Effect சரியான நேரத்தில் state update செய்தாலும் loop இன்னும் இருந்தால், அந்த state update Effect-ன் dependencies-இல் ஒன்றை மாற்றுவதால்தான். Dependency changes-ஐ debug செய்வது எப்படி என்பதை படிக்கவும்.


என் component unmount ஆகாதிருந்தாலும் cleanup logic run ஆகிறது

Cleanup function unmount போது மட்டும் அல்ல, dependencies மாறிய ஒவ்வொரு re-render-க்கும் முன்பும் run ஆகும். மேலும் development-இல், component mount ஆன உடனே React setup+cleanup-ஐ கூடுதலாக ஒருமுறை run செய்கிறது.

Corresponding setup code இல்லாமல் cleanup code இருந்தால், அது பொதுவாக code smell:

useEffect(() => {
// 🔴 Avoid: Cleanup logic without corresponding setup logic
return () => {
doSomething();
};
}, []);

உங்கள் cleanup logic setup logic-க்கு “symmetrical” ஆக இருக்க வேண்டும்; setup செய்ததை stop அல்லது undo செய்ய வேண்டும்:

useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);

Effect lifecycle component lifecycle-இலிருந்து எப்படி வேறுபடுகிறது என்பதை அறிக.


என் Effect visual ஏதாவது செய்கிறது; அது run ஆகும் முன் flicker தெரிகிறது

உங்கள் Effect browser screen-ஐ paint செய்வதை block செய்ய வேண்டும் என்றால், useEffect-ஐ useLayoutEffect-ஆக மாற்றுங்கள். பெரும்பாலான Effects-க்கு இது தேவையில்லை என்பதை கவனிக்கவும். Browser paint-க்கு முன் உங்கள் Effect run ஆகுவது மிக முக்கியமானபோது மட்டும் இது தேவைப்படும்: உதாரணமாக, user பார்க்கும் முன் tooltip-ஐ measure செய்து position செய்ய.