使用 api link 和接口作为参数,应用 Generec Typescript 检索数据
Apply Generec Typescript for retrieving data by using api link and interface as parameter
目标:
对于 React TS.
页面 List1 和 List2 应使用名为 useFetch 的相同方法(使用 api link 检索数据),方法是使用通用方法将接口(名为 Client 和 TheComputer)发送到 useFetch。
每个接口都有不同的数据成员。
您应该允许通过许多不同的接口名称使用 useFetch。
换句话说,
UseFetch 应该是一个独立的工具,可以通过发送 api link 和接口作为参数来被不同的接口使用。
问题:
您可以使用 React js 来实现它(不使用语法接口)但不能用于 React TS。
我在将 useFetch 作为 React TS 的独立组件时遇到问题。应该怎么解决?
其他信息:
*这是为 ReactJS 实现的,但不是为 ReactTS 实现的。
*不知何故,它在我的本地计算机上不起作用,可能是由于严格的 linting 和 TS 错误。
您需要使用接口来命令检索数据然后显示它。
*ReactTS 新手
谢谢!
Stackblitz:
JS
https://stackblitz.com/edit/react-mjvs38?
TS
https://stackblitz.com/edit/react-ts-7oeqen?
index.tsx
import React, { Component } from 'react';
import { render } from 'react-dom';
import {
BrowserRouter as Router,
Link,
Route,
Routes,
useParams,
} from 'react-router-dom';
import './style.css';
import useFetch1 from './useFetchTS1';
import useFetch2 from './useFetchTS2';
function App() {
return (
<div>
<h1>Home</h1>
</div>
);
}
function List1() {
const { data, loading, error } = useFetch1('https://api.github.com/users');
if (loading) {
return <div>Loading</div>;
}
return (
<div>
{data.map((item) => (
<div>
<img src={item.avatar_url} />
<div>{item.id}</div>
</div>
))}
;
</div>
);
}
function List2() {
const { data, loading, error } = useFetch2(
'https://jsonplaceholder.typicode.com/todos'
);
if (loading) {
return <div>Loading</div>;
}
return (
<div>
{data.map((item) => (
<div>
<div>
Id: {item.id} Title: {item.title}
</div>
</div>
))}
;
</div>
);
}
render(
<Router>
<div>
<header>
<Link to="/">Home</Link>
<br />
<Link to="/list1">List1</Link>
<br />
<Link to="/list2">List2</Link>
<br />
<hr />
</header>
<Routes>
<Route path="/" element={<App />} exact></Route>
<Route path="/list1" element={<List1 />} exact></Route>
<Route path="/list2" element={<List2 />}></Route>
</Routes>
</div>
</Router>,
document.getElementById('root')
);
useFetchTS1.tsx
import { useState, useEffect } from 'react';
interface Client {
id: number;
avatar_url: string;
}
export default function useFetch1(url) {
const [data, setData] = useState<Client[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function init() {
//debugger;
try {
const response = await fetch(url);
if (response.ok) {
const json = await response.json();
setData(json);
} else {
throw Response;
}
} catch (e) {
setError(e);
} finally {
setLoading(false);
}
}
init();
}, [url]);
return { data, error, loading };
}
useFetchTS2.tsx
import { useState, useEffect } from 'react';
interface TheComputer {
id: number;
title: string;
}
export default function useFetch2(url) {
const [data, setData] = useState<TheComputer[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function init() {
//debugger;
try {
const response = await fetch(url);
if (response.ok) {
const json = await response.json();
setData(json);
} else {
throw Response;
}
} catch (e) {
setError(e);
} finally {
setLoading(false);
}
}
init();
}, [url]);
return { data, error, loading };
}
有一种以前称为服务代理模式的设计可能适合您:
- 以标准方式使用 React,使用 useEffect 等
- 视图只需获取类型安全的数据并更新它们的模型
- Views 对 APIs 一无所知,只需询问代理 class
- 代理class可以表达API接口
- 较低级别的提取 class 可以以共享方式进行管道处理
要比较什么东西,看看我的代码是否有用:
在这些例子中:
- CompaniesContainer 是视图 class
- ApiFetch 发送和接收任何类型的 API 负载,并执行刷新 OAuth 令牌等常见任务
- ApiClient 确保视图仅使用类型安全的请求和响应
如果您愿意,可以将其中的一些改编成 React 挂钩。尽管我个人更喜欢将 React 语法限制为查看逻辑,并在其他地方使用纯 Typescript classes。然后我可以在其他类型的 UI 中使用等效的 classes,例如移动应用程序。
所以我相信如果我们将其更改为以下内容,我们可以让 useFetch 挂钩对您来说是通用的:
import { useEffect, useState } from 'react';
export default function useFetch1<TData = any>(url) {
const [data, setData] = useState<TData[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function init() {
//debugger;
try {
const response = await fetch(url);
if (response.ok) {
const json = await response.json();
setData(json);
} else {
throw Response;
}
} catch (e) {
setError(e);
} finally {
setLoading(false);
}
}
init();
}, [url]);
return { data, error, loading };
我们在函数定义中使用通用 并在数据的 useState 挂钩中使用 TData[]。
然后在您的 index.tsx 文件中,您可以在那里定义接口,并将它们传递给通用的 useFetch1 挂钩,如下所示:
useFetch1<Client>('https://api.github.com/users');
和
useFetch1<TheComputer>('https://jsonplaceholder.typicode.com/todos');
这让您可以使用通用的 useFetch 挂钩,并且仍然得到返回的正确数据 Interface/Type。
更新后的 index.tsx 文件如下所示:
import './style.css';
import {
Link,
Route,
BrowserRouter as Router,
Routes,
useParams,
} from 'react-router-dom';
import React, { Component } from 'react';
import { render } from 'react-dom';
import useFetch1 from './useFetchTS1';
interface Client {
id: number;
avatar_url: string;
}
interface TheComputer {
id: number;
title: string;
}
function App() {
return (
<div>
<h1>Home</h1>
</div>
);
}
function List1() {
const { data, loading, error } = useFetch1<Client>('https://api.github.com/users');
if (loading) {
return <div>Loading</div>;
}
return (
<div>
{data.map((item) => (
<div>
<img src={item.avatar_url} />
<div>{item.id}</div>
</div>
))}
;
</div>
);
}
function List2() {
const { data, loading, error } = useFetch1<TheComputer>(
'https://jsonplaceholder.typicode.com/todos'
);
if (loading) {
return <div>Loading</div>;
}
return (
<div>
{data.map((item) => (
<div>
<div>
Id: {item.id} Title: {item.title}
</div>
</div>
))}
;
</div>
);
}
render(
<Router>
<div>
<header>
<Link to="/">Home</Link>
<br />
<Link to="/list1">List1</Link>
<br />
<Link to="/list2">List2</Link>
<br />
<hr />
</header>
<Routes>
<Route path="/" element={<App />} exact></Route>
<Route path="/list1" element={<List1 />} exact></Route>
<Route path="/list2" element={<List2 />}></Route>
</Routes>
</div>
</Router>,
document.getElementById('root')
);
这利用了通用类型:https://www.typescriptlang.org/docs/handbook/2/generics.html
我也更新了 stackblitz,似乎可以正常工作:https://stackblitz.com/edit/react-ts-zasl3r?file=useFetchTS1.tsx
目标:
对于 React TS.
页面 List1 和 List2 应使用名为 useFetch 的相同方法(使用 api link 检索数据),方法是使用通用方法将接口(名为 Client 和 TheComputer)发送到 useFetch。
每个接口都有不同的数据成员。
您应该允许通过许多不同的接口名称使用 useFetch。
换句话说, UseFetch 应该是一个独立的工具,可以通过发送 api link 和接口作为参数来被不同的接口使用。
问题:
您可以使用 React js 来实现它(不使用语法接口)但不能用于 React TS。
我在将 useFetch 作为 React TS 的独立组件时遇到问题。应该怎么解决?
其他信息:
*这是为 ReactJS 实现的,但不是为 ReactTS 实现的。
*不知何故,它在我的本地计算机上不起作用,可能是由于严格的 linting 和 TS 错误。
您需要使用接口来命令检索数据然后显示它。
*ReactTS 新手
谢谢!
Stackblitz:
JS
https://stackblitz.com/edit/react-mjvs38?
TS
https://stackblitz.com/edit/react-ts-7oeqen?
index.tsx
import React, { Component } from 'react';
import { render } from 'react-dom';
import {
BrowserRouter as Router,
Link,
Route,
Routes,
useParams,
} from 'react-router-dom';
import './style.css';
import useFetch1 from './useFetchTS1';
import useFetch2 from './useFetchTS2';
function App() {
return (
<div>
<h1>Home</h1>
</div>
);
}
function List1() {
const { data, loading, error } = useFetch1('https://api.github.com/users');
if (loading) {
return <div>Loading</div>;
}
return (
<div>
{data.map((item) => (
<div>
<img src={item.avatar_url} />
<div>{item.id}</div>
</div>
))}
;
</div>
);
}
function List2() {
const { data, loading, error } = useFetch2(
'https://jsonplaceholder.typicode.com/todos'
);
if (loading) {
return <div>Loading</div>;
}
return (
<div>
{data.map((item) => (
<div>
<div>
Id: {item.id} Title: {item.title}
</div>
</div>
))}
;
</div>
);
}
render(
<Router>
<div>
<header>
<Link to="/">Home</Link>
<br />
<Link to="/list1">List1</Link>
<br />
<Link to="/list2">List2</Link>
<br />
<hr />
</header>
<Routes>
<Route path="/" element={<App />} exact></Route>
<Route path="/list1" element={<List1 />} exact></Route>
<Route path="/list2" element={<List2 />}></Route>
</Routes>
</div>
</Router>,
document.getElementById('root')
);
useFetchTS1.tsx
import { useState, useEffect } from 'react';
interface Client {
id: number;
avatar_url: string;
}
export default function useFetch1(url) {
const [data, setData] = useState<Client[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function init() {
//debugger;
try {
const response = await fetch(url);
if (response.ok) {
const json = await response.json();
setData(json);
} else {
throw Response;
}
} catch (e) {
setError(e);
} finally {
setLoading(false);
}
}
init();
}, [url]);
return { data, error, loading };
}
useFetchTS2.tsx
import { useState, useEffect } from 'react';
interface TheComputer {
id: number;
title: string;
}
export default function useFetch2(url) {
const [data, setData] = useState<TheComputer[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function init() {
//debugger;
try {
const response = await fetch(url);
if (response.ok) {
const json = await response.json();
setData(json);
} else {
throw Response;
}
} catch (e) {
setError(e);
} finally {
setLoading(false);
}
}
init();
}, [url]);
return { data, error, loading };
}
有一种以前称为服务代理模式的设计可能适合您:
- 以标准方式使用 React,使用 useEffect 等
- 视图只需获取类型安全的数据并更新它们的模型
- Views 对 APIs 一无所知,只需询问代理 class
- 代理class可以表达API接口
- 较低级别的提取 class 可以以共享方式进行管道处理
要比较什么东西,看看我的代码是否有用:
在这些例子中:
- CompaniesContainer 是视图 class
- ApiFetch 发送和接收任何类型的 API 负载,并执行刷新 OAuth 令牌等常见任务
- ApiClient 确保视图仅使用类型安全的请求和响应
如果您愿意,可以将其中的一些改编成 React 挂钩。尽管我个人更喜欢将 React 语法限制为查看逻辑,并在其他地方使用纯 Typescript classes。然后我可以在其他类型的 UI 中使用等效的 classes,例如移动应用程序。
所以我相信如果我们将其更改为以下内容,我们可以让 useFetch 挂钩对您来说是通用的:
import { useEffect, useState } from 'react';
export default function useFetch1<TData = any>(url) {
const [data, setData] = useState<TData[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function init() {
//debugger;
try {
const response = await fetch(url);
if (response.ok) {
const json = await response.json();
setData(json);
} else {
throw Response;
}
} catch (e) {
setError(e);
} finally {
setLoading(false);
}
}
init();
}, [url]);
return { data, error, loading };
我们在函数定义中使用通用
然后在您的 index.tsx 文件中,您可以在那里定义接口,并将它们传递给通用的 useFetch1 挂钩,如下所示:
useFetch1<Client>('https://api.github.com/users');
和
useFetch1<TheComputer>('https://jsonplaceholder.typicode.com/todos');
这让您可以使用通用的 useFetch 挂钩,并且仍然得到返回的正确数据 Interface/Type。
更新后的 index.tsx 文件如下所示:
import './style.css';
import {
Link,
Route,
BrowserRouter as Router,
Routes,
useParams,
} from 'react-router-dom';
import React, { Component } from 'react';
import { render } from 'react-dom';
import useFetch1 from './useFetchTS1';
interface Client {
id: number;
avatar_url: string;
}
interface TheComputer {
id: number;
title: string;
}
function App() {
return (
<div>
<h1>Home</h1>
</div>
);
}
function List1() {
const { data, loading, error } = useFetch1<Client>('https://api.github.com/users');
if (loading) {
return <div>Loading</div>;
}
return (
<div>
{data.map((item) => (
<div>
<img src={item.avatar_url} />
<div>{item.id}</div>
</div>
))}
;
</div>
);
}
function List2() {
const { data, loading, error } = useFetch1<TheComputer>(
'https://jsonplaceholder.typicode.com/todos'
);
if (loading) {
return <div>Loading</div>;
}
return (
<div>
{data.map((item) => (
<div>
<div>
Id: {item.id} Title: {item.title}
</div>
</div>
))}
;
</div>
);
}
render(
<Router>
<div>
<header>
<Link to="/">Home</Link>
<br />
<Link to="/list1">List1</Link>
<br />
<Link to="/list2">List2</Link>
<br />
<hr />
</header>
<Routes>
<Route path="/" element={<App />} exact></Route>
<Route path="/list1" element={<List1 />} exact></Route>
<Route path="/list2" element={<List2 />}></Route>
</Routes>
</div>
</Router>,
document.getElementById('root')
);
这利用了通用类型:https://www.typescriptlang.org/docs/handbook/2/generics.html
我也更新了 stackblitz,似乎可以正常工作:https://stackblitz.com/edit/react-ts-zasl3r?file=useFetchTS1.tsx