ReactJS useEffect Hook Sinhala Tutorial | Side Effects, Data Fetching & Cleanup

ReactJS useEffect Hook Sinhala Tutorial | Side Effects, Data Fetching & Cleanup

ආයුබෝවන් යාළුවනේ! ReactJS වල useEffect Hook එකට සාදරයෙන් පිලිගන්නවා!

ReactJS කියන්නේ Web Development ලෝකේ ජනප්‍රියම JavaScript library එකක් නේ. මේකේ functional components පාවිච්චි කරන අයට useEffect කියන්නේ නැතුවම බැරි Hook එකක්. අපිට React component එකක් ඇතුළේ කරන්න පුළුවන් සමහර දේවල් තියෙනවා, ඒවා component එකේ "rendering" එකට කෙලින්ම අදාළ නැහැ. මේවා අපි "Side Effects" කියලා හඳුන්වනවා. උදාහරණයක් විදිහට, API එකකින් Data Fetch කරන එක, Timers Set කරන එක, හෝ DOM එක Manual විදිහට Modify කරන එක වගේ දේවල්.

අද අපි මේ Guide එකෙන් බලමු, useEffect Hook එක කියන්නේ මොකක්ද, ඒකෙන් මොනවද කරන්න පුළුවන්, සහ ඒක හරියට පාවිච්චි කරන්නේ කොහොමද කියලා. ඒ වගේම, මේක පාවිච්චි කරනකොට එන්න පුළුවන් පොදු ගැටළු (Common Issues) සහ ඒවට විසඳුම් ගැනත් කතා කරමු. මේක ඔයාලගේ React Projects වලට ගොඩක් වැදගත් වෙයි කියලා මම විශ්වාස කරනවා!

Side Effects කියන්නේ මොනවාද?

සරලව කිව්වොත්, JavaScript වල "Pure Function" එකක් කියන්නේ, ඒකට දෙන Inputs අනුව හැමවෙලේම එකම Output එකක් දෙන, ඒ වගේම ඒකේ scope එකෙන් පිටත කිසිම දෙයක් වෙනස් නොකරන Function එකක්. React components සාමාන්‍යයෙන් මේ වගේ Pure Functions වෙන්න ඕන කියලා තමයි අපිට උපදෙස් දෙන්නේ.

ඒත් සමහර වෙලාවට අපිට component එකක් ඇතුළේ Pure නොවන වැඩ කරන්න වෙනවා. ඒවා තමයි Side Effects. මේවා React component එකක Rendering එකට කෙලින්ම අදාළ නැති, නමුත් component එකේ ජීවිත කාලය තුළ සිදුවිය යුතු ක්‍රියාවන් (actions). පොදු Side Effect උදාහරණ කීපයක් මෙන්න:

  • Data Fetching: Backend API එකකින් Data ගන්න එක (fetch, axios).
  • Subscriptions: Real-time updates, Event Listeners Set කරන එක.
  • Timers: setTimeout, setInterval පාවිච්චි කරන එක.
  • Manual DOM Manipulation: document.title වෙනස් කිරීම, Focus කිරීම.

React functional components වලදී මේ වගේ Side Effects handle කරන්න තමයි useEffect Hook එක නිර්මාණය කරලා තියෙන්නේ.

useEffect Hook එකට හැඳින්වීම

useEffect කියන්නේ React Hooks වලින් එකක්. මේකෙන් පුළුවන් Functional Components වලට "lifecycle methods" වලට සමාන දේවල් කරන්න. ඒ කියන්නේ, component එක Mount වෙනකොට, Update වෙනකොට, සහ Unmount වෙනකොට Side Effects Run කරන්න පුළුවන්.

useEffect Syntax එක

useEffect(callbackFunction, [dependencies]);
  • callbackFunction: මේක තමයි ඔයාගේ Side Effect එක අඩංගු function එක. මේක React මගින් Call කරනවා.
  • [dependencies]: මේක තමයි useEffect Hook එකේ තියෙන වැදගත්ම කොටසක්! මේක JavaScript Array එකක්. මේ Array එක ඇතුළේ තියෙන Values (Variables, Props, State Values) වලින් මොනවා හරි වෙනස් වුණොත් විතරයි callbackFunction එක ආයෙත් Run වෙන්නේ. මේකේ ක්‍රියාකාරීත්වය ගැන හොඳින් අවබෝධ කරගන්න එක අත්‍යවශ්‍යයි.
    • [] (Empty Dependency Array): මේක දුන්නොත්, useEffect එක Component එක මුලින්ම Render වෙනකොට (Mount වෙනකොට) එක පාරක් විතරයි Run වෙන්නේ. ඒක හරියට Class Components වල componentDidMount වගේ වැඩ කරනවා.
    • [someVar, someOtherVar] (With Dependencies): මේ වගේ Dependencies දුන්නොත්, Component එක Mount වෙනකොට වගේම, someVar හෝ someOtherVar කියන Values වලින් මොනවා හරි වෙනස් වුණොත් useEffect එක ආයෙත් Run වෙනවා. මේක componentDidUpdate වගේ වැඩ කරනවා.
    • no array (Dependency Array එකක් නොදුන්නොත්): මේක ඉතාම කලාතුරකින් පාවිච්චි කරන දෙයක්. Dependency Array එකක් නොදුන්නොත්, Component එක Render වෙන සෑම විටකම useEffect එක Run වෙනවා. මේක බොහෝ විට Infinite Loops වලට හේතුවක් වෙන්න පුළුවන් නිසා පරිස්සම් වෙන්න ඕනේ.

Cleanup Function එක

useEffect එකේ callbackFunction එකෙන් Return කරන්න පුළුවන් තවත් Function එකක් තමයි "Cleanup Function" එක. මේක වැදගත් වෙන්නේ Subscriptions, Timers, Event Listeners වගේ දේවල් Component එක Unmount වෙනකොට හෝ Dependencies වෙනස් වෙන්න කලින් Clear කරන්න ඕන වුණාමයි. මේක හරියට Class Components වල componentWillUnmount වගේ වැඩ කරනවා. ඒ වගේම, Dependencies වෙනස් වෙනකොට, අලුත් Effect එක Run වෙන්න කලින්, කලින් Effect එකේ Cleanup එක Run වෙනවා.

ප්‍රායෝගික උදාහරණ: API එකකින් Data Fetch කිරීම

අපි දැන් බලමු useEffect Hook එක පාවිච්චි කරලා API එකකින් Data Fetch කරන්නේ කොහොමද කියලා. අපි මේකට JSONPlaceholder කියන Public API එක පාවිච්චි කරමු. අපි Posts කීපයක් Fetch කරලා Display කරමු.

import React, { useState, useEffect } from 'react';
import axios from 'axios'; // Axios library එක install කරගෙන පාවිච්චි කරන්න, නැත්නම් fetch() පාවිච්චි කරන්න.

function DataFetcher() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    // මේක Mount වෙනකොට විතරයි Run වෙන්නේ, මොකද Dependency Array එක හිස්.
    // console.log("useEffect ran!"); // Debug කරන්න මේක පාවිච්චි කරන්න පුළුවන්

    const fetchPosts = async () => {
      try {
        const response = await axios.get('https://jsonplaceholder.typicode.com/posts?_limit=5');
        setPosts(response.data);
      } catch (err) {
        setError('Data fetch කිරිමේදී ගැටළුවක් ඇතිවිය: ' + err.message); // Localized error message
      } finally {
        setLoading(false);
      }
    };

    fetchPosts();

    // මේ සඳහා Cleanup function එකක් අත්‍යාවශ්‍ය නොවුනත්,
    // Request එකක් Abort කරන්න වගේ දේවල් වලට මෙතන Cleanup එකක් දෙන්න පුnලුවන්.
    return () => {
      // console.log("Cleanup for data fetch");
      // e.g., AbortController එකක් පාවිච්චි කරලා request එක cancel කරන්න පුළුවන්.
    };
  }, []); // හිස් Dependency Array එක නිසා Mount වෙනකොට විතරක් Run වෙනවා.

  if (loading) return <p>Data Loading වෙමින් පවතී...</p>;
  if (error) return <p style={{ color: 'red' }}>Error: {error}</p>;

  return (
    <div>
      <h2>JSONPlaceholder Posts</h2>
      <ul>
        {posts.map(post => (
          <li key={post.id}>
            <strong>{post.title}</strong>
            <p>{post.body}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default DataFetcher;

මේ Code එකේදී, useEffect එකේ Dependency Array එක [] (හිස්) විදිහට දීලා තියෙනවා. ඒ කියන්නේ, මේ fetchPosts function එක Run වෙන්නේ Component එක මුලින්ම Screen එකට Render (Mount) වෙනකොට විතරයි. ඊට පස්සේ Component එක Re-render වුණත්, මේ Effect එක ආයෙත් Run වෙන්නේ නැහැ. ඒකෙන් අනවශ්‍ය API Calls වලක්වනවා.

Cleanup Function එකේ වැදගත්කම

Timers, Event Listeners, Subscriptions වගේ දේවල් Component එක Unmount වෙනකොට හෝ Dependencies වෙනස් වෙනකොට හරියට Clear නොකළොත් Memory Leaks හෝ අනපේක්ෂිත ක්‍රියා (Unexpected Behaviour) ඇති වෙන්න පුළුවන්. Cleanup Function එකෙන් මේ වගේ දේවල් වළක්වනවා.

සරල Timer එකක් පාවිච්චි කරලා Cleanup Function එකක ක්‍රියාකාරීත්වය බලමු.

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

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

  useEffect(() => {
    // Interval එකක් සෙට් කරනවා
    const intervalId = setInterval(() => {
      setCount(prevCount => prevCount + 1); // prevCount පාවිච්චි කරන්නේ Stale Closures වළක්වන්න.
    }, 1000);

    // Cleanup function එක
    return () => {
      console.log("Timer එක Clear කලා! Interval ID:", intervalId); // Localized message
      clearInterval(intervalId); // Timer එක නවත්වනවා
    };
  }, []); // හිස් Dependency Array එක: Mount වෙනකොට පටන් ගන්නවා, Unmount වෙනකොට Clear වෙනවා.

  return (
    <div>
      <h2>Timer එක</h2>
      <p>Count: {count}</p>
      <p>Component එක unmount වෙනකොට හෝ refresh වෙනකොට Timer එක clear වෙනවා.</p>
    </div>
  );
}

export default TimerComponent;

මේ උදාහරණයේදී, අපි setInterval එකක් පාවිච්චි කරලා Count එක වැඩි කරනවා. useEffect එකෙන් Return කරන Cleanup Function එක, Component එක Screen එකෙන් අයින් වෙනකොට (Unmount වෙනකොට) clearInterval Call කරලා Timer එක නවත්තනවා. මේක නොකළොත්, Component එක අයින් වුණත් Timer එක දිගටම Run වෙමින් Memory Leak එකක් ඇති කරන්න පුළුවන්.

පොදු ගැටළු සහ හොඳම ක්‍රම (Common Issues & Best Practices)

useEffect Hook එක powerful වුණත්, ඒක හරියට තේරුම් අරගෙන පාවිච්චි නොකළොත් සමහර Common Issues වලට මුහුණ දෙන්න පුළුවන්.

Infinite Loops

මේක useEffect පාවිච්චි කරනකොට එන පොදුම ගැටලුවක්. මේක ඇති වෙන්නේ Dependency Array එකක් නොදුන්නොත් හෝ වැරදි Dependency එකක් දුන්නොත්.

උදාහරණයක් විදිහට, useEffect එක ඇතුළේ State එකක් Update කරලා, ඒ Update කරපු State එක Dependency විදිහට දුන්නොත්, State එක Update වෙලා Component එක Re-render වෙලා useEffect එක ආයෙත් Run වෙලා State එක ආයෙත් Update වෙලා... මේ විදිහට Loop එකක් ඇති වෙන්න පුළුවන්.

useEffect(() => {
  setCount(count + 1); // මේක Infinite Loop එකකට හේතු වෙන්න පුළුවන්
}, [count]); // 'count' වෙනස් වෙනකොට Run වෙනවා, ඒත් 'count' හැම වෙලේම වෙනස් වෙනවා!

මේ වගේ තැන් වලදී useState වල Updater Function එක පාවිච්චි කරන එක වඩා හොඳයි:

useEffect(() => {
  const intervalId = setInterval(() => {
    setCount(prevCount => prevCount + 1); // මෙතන 'count' dependency එකක් විදිහට අවශ්‍ය නැහැ.
  }, 1000);
  return () => clearInterval(intervalId);
}, []); // දැන් 'count' dependency එකක් නොවන නිසා Infinite Loop එකක් නැහැ.

Stale Closures (පරණ Values පාවිච්චි වීම)

useEffect එකක් Run වෙනකොට, ඒක ඒ වෙලාවේ තිබුණු State Values සහ Props ටික "Capture" කරගන්නවා. අපි Dependency Array එකට මේ Values ටික නොදුන්නොත්, useEffect එක ඇතුළේ පරණ State අගයන් හෝ Props පාවිච්චි වෙන්න පුළුවන්. මේකට "Stale Closure" කියලා කියනවා.

උදාහරණයක් විදිහට:

function MyComponent() {
  const [value, setValue] = useState(0);

  useEffect(() => {
    const timer = setTimeout(() => {
      console.log('Current value:', value); // 'value' එක update වුණත්, මෙතන පරණ 'value' එක පෙන්නන්න පුළුවන්.
    }, 2000);
    return () => clearTimeout(timer);
  }, []); // 'value' dependency එකක් විදිහට නැති නිසා, 'value' හි මුල් අගය (0) Capture කරගන්නවා.

  return (
    <div>
      <p>Value: {value}</p>
      <button onClick={() => setValue(value + 1)}>Increment</button>
    </div>
  );
}

මේක විසඳන්න, value එක useEffect එකේ Dependency Array එකට එකතු කරන්න ඕන. එතකොට value වෙනස් වෙන හැමවිටම useEffect එක ආයෙත් Run වෙලා අලුත් value එක Capture කරගන්නවා.

// ... (ඉහත කෝඩ් එකේම කොටසක්)
  useEffect(() => {
    const timer = setTimeout(() => {
      console.log('Current value:', value); // දැන් අලුත්ම 'value' එක පෙන්නයි.
    }, 2000);
    return () => clearTimeout(timer);
  }, [value]); // 'value' Dependency විදිහට දුන්නා.

ඔයාලාගේ Project එකේදී ESLint වගේ Tools පාවිච්චි කරනවා නම්, eslint-plugin-react-hooks කියන Plugin එකෙන් මේ වගේ Dependencies අමතක වුණාම Warnings පෙන්නනවා. ඒ නිසා ඒ Warnings වලට අවධානය යොමු කිරීම වැදගත්.

`useEffect` Runs වෙන්නේ කවදාද?

useEffect එකේ callbackFunction එක, Component එක මුලින්ම Render වුණාට පස්සේ සහ DOM එක Update වුණාට පස්සේ තමයි Run වෙන්නේ. ඒ වගේම, Dependency Array එකේ තියෙන Values වෙනස් වුණාම ආයෙත් Run වෙනවා. Cleanup Function එක Run වෙන්නේ ඊළඟ Render එකට කලින් හෝ Component එක Unmount වෙන්න කලින්.

අවසන් වශයෙන්

useEffect Hook එක React functional components වල Side Effects effectively handle කරන්න පුළුවන් ඉතාම බලවත් Tool එකක්. මේක හරියට තේරුම් අරගෙන පාවිච්චි කරන එක ඔයාලගේ React development experience එකට ගොඩක් වැදගත්. Dependency Array එකේ වැදගත්කම සහ Cleanup Function එකේ අවශ්‍යතාවය හොඳින් අවබෝධ කරගන්න එක අත්‍යාවශ්‍යයි.

ඔයාලා මේ concepts ඔයාලගේ project වලට implement කරලා බලන්න. මොනවා හරි ප්‍රශ්න තිබුණොත් හෝ අත්දැකීම් බෙදාගන්න ඕන නම් comment section එකේ අහන්න! අපි උදව් කරන්න සූදානම්.

ඉස්සරහටත් මේ වගේ React tutorial එකකින් හම්බවෙමු! ඔබට ජය!