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 ;
}