Reputation: 21
I created a custom hook to fetch an API and I wanna pass the data to the component and getting this type of error. I'm new to react and typescript
my custom useFetch code:
import { useEffect, useState } from "react";
export interface IBlog {
data: {
title: string;
body: string;
author: string;
id: number
url: string;
}[]
}
const useFetch = (url: string) => { // url: string
const [data, setData] = useState<IBlog['data']>([]);
const [isPending, setIsPending] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const abortController = new AbortController();
setTimeout(() => {
fetch(url, { signal: abortController.signal })
.then(res => {
if (!res.ok) { // error coming back from server
throw Error('could not fetch the data for that resource');
}
return res.json();
})
.then(data => {
setIsPending(false);
setData(data);
setError(null);
})
.catch(err => {
if (err.name === "AbortError") {
console.log('fech aborted');
} else {
// auto catches network / connection error
setIsPending(false);
setError(err.message);
}
})
}, 1000);
// cleanup funtion
return () => abortController.abort();
}, [url])
return [data, isPending, error]
}
export default useFetch
and this is the component where I want to pass the data and getting my error
import BlogList from "./BlogList";
import useFetch from "./useFetch";
import React, { FC } from 'react';
import { IBlog } from "./useFetch"
const Home: FC = () => {
const [data, isPending, error] = useFetch("http://localhost:8000/blogs")
console.log(data, isPending, error, "from hook")
return (
<div className='home'>
{error && <div>{error}</div>}
{isPending && <div>loading...</div>}
{data && <BlogList data={data} />}
</div>
)
}
export default Home
and this is the component to display my data
import BlogList from "./BlogList";
import useFetch from "./useFetch";
import React, { FC } from 'react';
import { IBlog } from "./useFetch"
const Home: FC = () => {
const [data, isPending, error] = useFetch("http://localhost:8000/blogs")
console.log(data, isPending, error, "from hook")
return (
<div className='home'>
{error && <div>{error}</div>}
{isPending && <div>loading...</div>}
{data && <BlogList data={data} />}
</div>
)
}
export default Home
Error messege
Failed to compile
C:/Users/63906/Documents/Web Development/citcs-blogs/src/components/Home.tsx
TypeScript error in C:/Users/63906/Documents/Web Development/citcs-blogs/src/components/Home.tsx(16,26):
Type 'true | { title: string; body: string; author: string; id: number; url: string; }[]' is not assignable to type '{ title: string; body: string; author: string; id: number; url: string; }[]'.
Type 'boolean' is not assignable to type '{ title: string; body: string; author: string; id: number; url: string; }[]'. TS2322
14 | {error && <div>{error}</div>}
15 | {isPending && <div>loading...</div>}
> 16 | {data && <BlogList data={data} title='All Blogs!' />}
| ^
17 | </div>
18 | )
19 | }
Upvotes: 2
Views: 3047
Reputation: 8340
The problem is you're returning a mutable array from useFetch
custom hook. And it's type gets inferred as a union of all types of the values it contains:
/*
const useFetch: (url: string) => (boolean | {
title: string;
body: string;
author: string;
id: number;
url: string;
}[] | null)[]
*/
const useFetch = (url: string) => {
...
return [data, isPending, error];
};
To fix the issue you just have to annotate it as a readonly type:
/*
const useFetch: (url: string) => readonly [{
title: string;
body: string;
author: string;
id: number;
url: string;
}[], boolean, null]
*/
const useFetch = (url: string) => {
...
return [data, isPending, error] as const;
};
Upvotes: 1