如何使我的 axios 函数可在其他 React/Typescript 组件中重用?
How can I make my axios function reusable in other React/Typescript components?
我是 copying/pasting 在多个组件中发出 axios 请求的相同代码,如下所示:
React.useEffect(() => {
axios
.get<IDownloads[]>(`${process.env.PUBLIC_URL}/api/downloads`, {
headers: {
'Content-Type': 'application/json',
},
timeout: 5000,
})
.then((response) => {
setFaqs(response.data);
})
.catch((ex) => {
const err = axios.isCancel(ex)
? 'Request cancelled'
: ex.code === 'ECONNABORTED'
? 'A timeout has occurred'
: ex.response.status === 404
? 'Resource not found'
: 'An unexpected error has occurred';
setError(err);
});
}, []);
哪个有效,但不遵循 DRY。我希望能够在我的应用程序的其他区域重用此代码,但需要能够更改 .get(${process.env.PUBLIC_URL}/api/downloads
以在其他区域工作。像 .get (${process.env.PUBLIC_URL}/api/somethingElse
我制作了一个新组件试图做到这一点
export default function useApiRequest<T>(url: string): { response: T | null; error: Error | null} {
const [response, setResponse] = React.useState<T | null>(null);
const [error, setError] = React.useState<Error | null>(null);
React.useEffect(() => {
const fetchData = async (): Promise<void> => {
try {
const res = await axios(`${process.env.PUBLIC_URL}${url}`);
setResponse(res.data);
} catch (error) {
setError(error);
}
};
fetchData();
}, [url]);
return { response, error };
};
并像这样在这个组件中使用它:
interface IDownloads {
db_id: number;
file_description: string;
file_name: string;
developer_name: string;
date_uploaded: string;
file_url: string;
}
const defaultProps: IDownloads[] = [];
const DownloadCodeSamplesPage: React.FC = () => {
const downloadQuery = useApiRequest<IDownloads[]>('/api/download');
const [downloads, setDownloads]: [IDownloads[], (posts: IDownloads[]) => void] =
React.useState(defaultProps);
在我的 return 中,我正在通过下载映射
downloads.map((download) => (
<tr key={download.db_id}>
<td>{download.file_description}</td>
<td>{download.file_name}</td>
<td>{download.developer_name}</td>
<td>{download.date_uploaded}</td>
当我 运行 程序时,我没有收到来自 api 调用的任何数据。我做错了什么?
状态复制
你的钩子看起来很棒。问题在于您如何在组件中使用它。 您不需要 downloads
的本地状态——这就是关键所在!所以杀了那个 React.useState
和你打电话的地方 setDownloads
.
您可以从挂钩访问 downloads
,如果它是 null
,则将其替换为空数组。
const downloads = downloadQuery.response ?? [];
const DownloadCodeSamplesPage: React.FC = () => {
const downloadQuery = useApiRequest<IDownloads[]>("/api/download");
const downloads = downloadQuery.response ?? [];
return (
<table>
<tbody>
{downloads.map((download) => (
<tr key={download.db_id}>
<td>{download.file_description}</td>
<td>{download.file_name}</td>
<td>{download.developer_name}</td>
<td>{download.date_uploaded}</td>
</tr>
))}
</tbody>
</table>
);
};
您可以考虑为您的网站创建一个预先配置了 baseUrl
和任何其他设置的 axios instance,并在您的应用程序的任何地方使用它。
我是 copying/pasting 在多个组件中发出 axios 请求的相同代码,如下所示:
React.useEffect(() => {
axios
.get<IDownloads[]>(`${process.env.PUBLIC_URL}/api/downloads`, {
headers: {
'Content-Type': 'application/json',
},
timeout: 5000,
})
.then((response) => {
setFaqs(response.data);
})
.catch((ex) => {
const err = axios.isCancel(ex)
? 'Request cancelled'
: ex.code === 'ECONNABORTED'
? 'A timeout has occurred'
: ex.response.status === 404
? 'Resource not found'
: 'An unexpected error has occurred';
setError(err);
});
}, []);
哪个有效,但不遵循 DRY。我希望能够在我的应用程序的其他区域重用此代码,但需要能够更改 .get${process.env.PUBLIC_URL}/api/downloads
以在其他区域工作。像 .get${process.env.PUBLIC_URL}/api/somethingElse
我制作了一个新组件试图做到这一点
export default function useApiRequest<T>(url: string): { response: T | null; error: Error | null} {
const [response, setResponse] = React.useState<T | null>(null);
const [error, setError] = React.useState<Error | null>(null);
React.useEffect(() => {
const fetchData = async (): Promise<void> => {
try {
const res = await axios(`${process.env.PUBLIC_URL}${url}`);
setResponse(res.data);
} catch (error) {
setError(error);
}
};
fetchData();
}, [url]);
return { response, error };
};
并像这样在这个组件中使用它:
interface IDownloads {
db_id: number;
file_description: string;
file_name: string;
developer_name: string;
date_uploaded: string;
file_url: string;
}
const defaultProps: IDownloads[] = [];
const DownloadCodeSamplesPage: React.FC = () => {
const downloadQuery = useApiRequest<IDownloads[]>('/api/download');
const [downloads, setDownloads]: [IDownloads[], (posts: IDownloads[]) => void] =
React.useState(defaultProps);
在我的 return 中,我正在通过下载映射
downloads.map((download) => (
<tr key={download.db_id}>
<td>{download.file_description}</td>
<td>{download.file_name}</td>
<td>{download.developer_name}</td>
<td>{download.date_uploaded}</td>
当我 运行 程序时,我没有收到来自 api 调用的任何数据。我做错了什么?
状态复制
你的钩子看起来很棒。问题在于您如何在组件中使用它。 您不需要 downloads
的本地状态——这就是关键所在!所以杀了那个 React.useState
和你打电话的地方 setDownloads
.
您可以从挂钩访问 downloads
,如果它是 null
,则将其替换为空数组。
const downloads = downloadQuery.response ?? [];
const DownloadCodeSamplesPage: React.FC = () => {
const downloadQuery = useApiRequest<IDownloads[]>("/api/download");
const downloads = downloadQuery.response ?? [];
return (
<table>
<tbody>
{downloads.map((download) => (
<tr key={download.db_id}>
<td>{download.file_description}</td>
<td>{download.file_name}</td>
<td>{download.developer_name}</td>
<td>{download.date_uploaded}</td>
</tr>
))}
</tbody>
</table>
);
};
您可以考虑为您的网站创建一个预先配置了 baseUrl
和任何其他设置的 axios instance,并在您的应用程序的任何地方使用它。