Full Stack Development

useEffect - Lifecycle

by Tomas Trescak t.trescak@westernsydney.edu.au

Component Lifecycle

  • Mounting
    • Render
    • Commit
  • Updating
    • Cleanup
    • Render
    • Commit
  • Unmounting
    • Cleanup

Lifecycle


      import React, 
  { render, useState, useEffect } from "react";

function getCount() {
    return document.querySelector("p")?.innerText;
}

const LifecycleDemo = () => {
  const [count, setCount] = useState(0);

  // Runs during rendering
  console.log("Rendering: " + getCount())

  // Runs only once when the component is mounted
  useEffect(() => {
    console.log("Mounted: " + getCount());

    // Cleanup: Runs when the component unmounts
    return () => {
      console.log("Unmounted");
    };
  }, []); // Dependency array is empty, 
          // so it runs only on mount and unmount.

  // Runs every time 'count' changes
  useEffect(() => {
    console.log(`Updated to "${getCount()}"`);

    // Cleanup: Runs before the next effect or on unmount
    return () => {
      console.log(`Cleanup count changes or unmount: ${count}`);
    };
  }, [count]); // Dependency array has 'count', 
               // so it runs when 'count' changes.

  return (
    <div>
      <h1>React Lifecycle with useEffect</h1>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
};

function App() {
  const [show, setShow] = useState(true);
  return (
    <>
      {show && <LifecycleDemo />}
      <button onClick={() => setShow(!show)}>Toggle</button>
    </>
  )
}

render(<App />)
    

Lifecycle /

Example

      import { render, useState, useEffect } from "react";

// Custom Hook: Fetches data from an API
const useFetch = (url) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    let isCancelled = false;

    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error(
            `HTTP error! Status: ${response.status}`
          );
        }
        const result = await response.json();
        if (!isCancelled) {
          setData(result);
        }
      } catch (err) {
        if (!isCancelled) {
          setError(err.message);
        }
      } finally {
        if (!isCancelled) {
          setLoading(false);
        }
      }
    };

    fetchData();

    // Cleanup function to cancel updates if the component unmounts
    return () => {
      isCancelled = true;
    };
  }, [url]); // Re-run when the URL changes

  return { data, loading, error };
};

const App = () => {
  const { data, loading, error } = useFetch(
    "https://jsonplaceholder.typicode.com/posts"
  );

  return (
    <div>
      <h1>Data Fetch Hook Example</h1>
      {loading && <p>Loading...</p>}
      {error && <p style={{ color: "red" }}>Error: {error}</p>}
      {data && (
        <ul>
          {data.slice(0, 5).map((post) => (
            <li key={post.id}>
              <strong>{post.title}</strong>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
};

render(<App />)