Home > Net >  how to run a custom hook when a prop changes?
how to run a custom hook when a prop changes?

Time:12-03

I created a custom hook which takes a url and return the data

import { useEffect, useState } from "react";

export function useHttp({ url }: { url: string }) {
  const [data, setData] = useState<any>(null);

 useEffect(() => {
    const controller = new AbortController();
    const signal = controller.signal;
    fetch(url, { signal })
      .then((res) => res.json())
      .then((data) => setData(data))
      .catch((err) => {
        if (err.name === "AbortError") {
          console.log("successfully aborted");
        } else {
          // handle error
        }
      });

    return () => {
      // cancel the request before component unmounts
      controller.abort();
    };
  }, []);

  return data ;
}

I'm using the hook to fetch data in my main page, this works fine

import { useState } from "react";
import { useHttp } from "./useHttp";
import "./App.css";

type person = { name: string; id: number };
function App() {
  const [selectedId, setSelectedId] = useState<number>(1);
  const people = useHttp({ url: "https://jsonplaceholder.typicode.com/users" });

  return (
    <div className="App">
      {(people as unknown as person[])?.map(({ id, name }) => (
        <button key={id} onClick={() => setSelectedId(id)}>
          {name}
        </button>
      ))}
      <br />
      <InnerComponent selectedId={selectedId} />
    </div>
  );
}

The part where I'm stuck is, I'm trying to reuse the hook again in a child component to fetch detail about depending on some value from the main component


const InnerComponent = ({ selectedId }: { selectedId: number }) => {
  console.log(selectedId)
  const person = useHttp({
    url: `https://jsonplaceholder.typicode.com/users/${selectedId}`,
  });

  return <div>{person?.name}</div>;
};

also I can seen that the prop value has changed, my hook doesn't rerun, how can I implement that without rewriting the logic in useEffect?

I expected the hook to rerun when the prop changes and fetch me the result, but it only runs once in the initial render

CodePudding user response:

Like the other answer says, your hook depends on the url param, so it should be included in the dependency array of the useEffect call.

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

Additionally, you should take some time to learn how to configure eslint in your project. The default eslint config in most templates will force you to include all dependencies in the dependency array. This way you won't have to remember to do this manually every time.

CodePudding user response:

Use the dependency array

export function useHttp({ url }: { url: string }) {
  const [data, setData] = useState<any>(null);

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

  return data ;
}
  • Related