我目前正在从事一个项目,我有一个 api 模块,其中包含我在应用程序中使用的所有端点的类型和返回类型。从我的 api 获取数据时,我看到自己重复了很多逻辑,这就是为什么我想制作一个 react-hook 来使这更容易一些。
我认为第一个参数应该是要调用的函数,下一个参数是要传递给该函数的参数数组。由于每个 api 函数采用的参数不同,我很乐意根据作为第一个参数传递的函数来推断参数的类型。我也希望我从钩子(Hook)返回的数据与调用的函数相对应。
例如,如果端点返回 Promise<User>
, 我希望数据是用户类型。
这是我想要完成的事情的一个最小示例,它处于非工作状态,因为我一直在努力让输入正常工作。
我想象它是如何工作的
function App() {
const user = useApi(api.getUser, "123");
if (user.loading) return <p>Loading...</p>;
if (user.error) return <p>{user.error}</p>;
return (
<div className="App">
<h1>Hello {user.data.name}</h1>
</div>
);
}
API
type User = {
name: string;
age: number;
};
function getUser(userId: string): Promise<User> {
return Promise.resolve({ name: "Peter", age: 20 });
}
function getFamilyMembers(userId: string): Promise<User[]> {
return Promise.resolve([
{ name: "Jackie", age: 17 },
{ name: "John", age: 42 }
]);
}
使用 Api-hook
const useApi = (apiCall: keyof typeof api, arguments: any[]) => {
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState("");
const [data, setData] = React.useState();
React.useEffect(() => {
// Fetch data from api and set state
apiCall(...arguments)
.then(res => setData(res))
.catch(err => setError("Something bad happened :("))
.finally(() => setLoading(false));
}, []);
return {
loading,
error,
data
};
};
我还在 codesandbox 上创建了最小示例
最佳答案
我认为这不是 100% 可行的,至少现在还不是。至少您可以获得良好的数据类型。
您实质上要求的是一种定义 apiCall
的方法,以便它采用一些未知数量和类型的参数以及匹配参数的函数。这些通常是可变参数函数,目前在 TypeScript ( but they're coming ) 中不是这样。
关键是泛型类型,你可以做的是使用可变参数函数并解决缺乏类型安全的问题。这看起来像...
export const useApi = useApiImpl;
function useApiImpl<TReturn>(apiCall: (...a: any[]) => Promise<TReturn>, defaultState: TReturn, ...args: any[]) {
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState("");
const [data, setData] = React.useState(defaultState);
React.useEffect(() => {
// Fetch data from api and set state
apiCall(...args)
.then(res => setData(res))
.catch(err => setError("Something bad happened :("))
.finally(() => setLoading(false));
}, []);
return {
loading,
error,
data
};
};
apiCall
成为一个接受一些参数并返回某种 promise 的函数,而 args
是一些要传递的参数集。您需要采用显式默认状态(或以其他方式约束 TReturn
并添加一些强制转换)以获得对 data
和 setData
的可靠类型推断.公平警告,我的 React 不是很强大,所以我只是猜测 React.useState(defaultState)
是正确的。
现在,理论上,当通用可变元组类型可用时,您将能够编写 useApiImpl
as
function useApiImpl<TArgs extends unknown[], TReturn>(apiCall: (...a: TArgs[]) => Promise<TReturn>, defaultState: TReturn, ...args: TArgs[]) {
// otherwise the same
};
我实际上无法测试它,因此声明可能与实际发布的有所不同,但基本上您将能够将 TArgs
绑定(bind)到集合泛型类型,然后要求 apiCall
采用与传递给 args
中的 useApiImpl
相同的类型(作为参数)。
关于reactjs - 具有类型支持的可重用 api Hook ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62519666/
相关文章:
apache-kafka - 为什么 KSQL 查询从流-流连接创建的流中返回空值?
python - 如何在 python 中使用 altair 包加载和绘制 csv 文件?
java - 如何在 Tycho 构建中设置 Java 编译器兼容性?
node.js - 如何在 Couchbase NodeJS SDK 3X 中设置 operatio
git - $(NugetPackageRoot) 宏在 VS2019 中自动更改为 *.sfpro
android - React Native & Socket.io - 无法在应用程序和服务器之间