React Query
React Query 是一个强大的数据同步库,用于在 React 应用程序中处理服务器状态的获取、缓存和更新。它提供了一系列的 hooks,使得在组件中获取和操作远程数据变得更加简单和高效。React Query 自动处理数据获取过程中的缓存、重试、更新和失效等问题,极大地简化了数据管理逻辑。
查看更多相关内容
如何在react-querybuilder中使用API和multiselect实现自动完成?
在React中使用react-querybuilder结合API和multiselect创建一个自动完成功能,我们通常会遵循以下步骤:
#### 1. 安装必要的依赖
首先,确保安装了 `react-querybuilder`,并且如果我们要使用multiselect,我们可能会使用如 `react-select`来实现这一功能。可以通过npm或yarn进行安装:
```bash
npm install react-querybuilder react-select
# 或者
yarn add react-querybuilder react-select
```
#### 2. 设置API
为了实现自动完成,你需要有一个API端点来搜索或过滤数据。这个API应该能根据用户输入的查询参数返回匹配的结果。例如,一个简单的API可能接收一个查询字符串,并返回匹配的选项列表。
```javascript
// 示例 API 调用函数
async function fetchOptions(query) {
const response = await fetch(`https://your-api.com/options?search=${query}`);
const data = await response.json();
return data.options; // 假设返回的数据是一个包含选项的数组
}
```
#### 3. 集成 `react-select`到 `react-querybuilder`
在 `react-querybuilder`中,你可以通过自定义输入组件来集成 `react-select`。这里,我们将创建一个自动完成的下拉菜单,用户在输入时会调用API并显示匹配的选项。
```javascript
import Select from 'react-select';
import { useState, useEffect } from 'react';
const AutocompleteSelect = ({ field, operator, value, setValue }) => {
const [options, setOptions] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (value) {
fetchOptions(value).then(data => {
setOptions(data.map(option => ({ label: option, value: option })));
setLoading(false);
});
}
}, [value]);
const handleInputChange = (inputValue) => {
setLoading(true);
fetchOptions(inputValue).then(data => {
setOptions(data.map(option => ({ label: option, value: option })));
setLoading(false);
});
};
return (
<Select
options={options}
isLoading={loading}
onInputChange={handleInputChange}
onChange={(selected) => setValue(selected.value)}
value={options.find(option => option.value === value)}
/>
);
};
```
#### 4. 将自定义组件应用于QueryBuilder
现在你可以在QueryBuilder中使用你的自定义AutocompleteSelect组件来实现自动完成。
```javascript
import QueryBuilder from 'react-querybuilder';
const App = () => {
return (
<QueryBuilder
fields={[{ name: 'field1', label: 'Field 1' }]}
controlElements={{
valueEditor: AutocompleteSelect
}}
/>
);
};
```
#### 5. 测试并优化
最后,确保你的实现在各种情况下都能正常工作。注意处理错误、空结果和网络延迟等情况。你可能还想加入缓存机制,以避免API的频繁调用。
#### 结论
通过上述步骤,我们成功地在react-querybuilder中集成了一个API-backed的multiselect自动完成功能。此功能增强了用户体验,使用户能够方便快捷地从大量数据中筛选和选择。在实际应用中,你可能需要根据具体需求调整API和组件的配置。
阅读 6 · 8月23日 22:51
ReactQuery使用旧数据进行重提取
React Query 是一个强大的库,用于在 React 应用中处理服务器状态的获取、缓存和更新。当涉及到使用旧数据进行重提取时,React Query 提供了几种有效的方法来确保应用的数据既是最新的,又能提供良好的用户体验。我将从以下几个方面来详细解释:
#### 1. **背景理解**
React Query 默认使用**乐观更新**(Optimistic Updates)策略,即在发出新的数据请求之前,暂时使用旧数据作为当前显示的内容。这种方法可以减少界面抖动和加载状态,改善用户的体验。
#### 2. **使用旧数据的场景**
- **用户界面持续性**:在数据刷新或重提取时,使用旧数据可以保持用户界面的连续性,避免数据刷新带来的闪烁感。
- **性能优化**:在等待新数据加载时,先展示旧数据可以减少白屏时间,提升用户感知的性能。
#### 3. **功能实现**
在 React Query 中,我们可以通过设置 `staleTime` 和 `cacheTime` 这两个参数来控制数据的新鲜度和缓存时长。例如:
```javascript
useQuery('todos', fetchTodos, {
staleTime: 300000, // 数据在5分钟内被认为是新鲜的
cacheTime: 900000 // 缓存保持15分钟
});
```
在这个例子中,即使数据源已经有所更新,用户在5分钟内不会感知到任何变化,这就是利用旧数据来优化体验。
#### 4. **重提取策略**
React Query 在进行数据重提取时,有几种策略可以选择:
- **On Window Focus**:当窗口重新获得焦点时触发数据重提取。
- **On Network Reconnect**:在网络重新连接时触发数据重提取。
- **Polling**:定时轮询数据。
这些策略可以与旧数据的使用结合起来,以保持数据的实时性,同时不牺牲用户体验。
#### 5. **实例解释**
假设我们有一个新闻应用,用户正在阅读一篇文章。如果每次数据更新都立即影响到用户正在阅读的页面,可能会引起用户的不适。在这种情况下,使用 React Query 的旧数据显示,结合轻微的背景数据更新(比如每10分钟检查一次新数据),可以大大提升用户体验。
#### 总结
React Query 的旧数据重提取机制不仅能够确保数据的实时性,还可以有效地平衡数据的实时更新和用户体验之间的矛盾。通过合理配置 `staleTime`、`cacheTime` 以及合适的重提取策略,可以让 React 应用更加高效和友好。
阅读 5 · 8月23日 22:50
如何使用“react-query”和“type-script”上传文件?
在使用 React Query 和 TypeScript 上传文件时,首先需要确保你已经在你的项目中安装了 `react-query` 和设置了 TypeScript。接下来,我将分步骤详细地解释整个过程:
### 第一步:创建服务函数来处理文件上传
在使用 React Query 上传文件之前,我们需要先创建一个函数来处理实际的文件上传逻辑。这通常涉及到使用 `fetch` API 或者其他库(如 axios)来发送一个 POST 请求到服务器。
这里是一个使用 `fetch` 和 `FormData` 的 TypeScript 示例函数:
```typescript
interface UploadResponse {
success: boolean;
message: string;
url?: string;
}
async function uploadFile(file: File): Promise<UploadResponse> {
const formData = new FormData();
formData.append("file", file);
const response = await fetch("https://your-upload-endpoint.com", {
method: "POST",
body: formData,
});
if (!response.ok) {
throw new Error('Failed to upload file');
}
return response.json();
}
```
### 第二步:使用 React Query 的 `useMutation` 钩子
React Query 的 `useMutation` 钩子非常适合处理这种可能改变服务器状态的异步操作,如文件上传。通过使用 `useMutation`,我们可以轻松地追踪上传状态、错误处理和数据更新。
在组件中,你可以如下使用这个钩子和上传函数:
```typescript
import { useMutation } from 'react-query';
const FileUploader: React.FC = () => {
const { mutate, isLoading, isError, error, isSuccess } = useMutation(uploadFile);
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files?.length) {
const file = event.target.files[0];
mutate(file); // 调用上传函数
}
};
return (
<div>
<input type="file" onChange={handleFileChange} />
{isLoading && <p>Uploading...</p>}
{isError && <p>Error: {error instanceof Error ? error.message : 'Unknown error'}</p>}
{isSuccess && <p>Upload successful!</p>}
</div>
);
};
```
### 第三步:处理上传状态的反馈
如上面代码中所示,我们可以通过 `isLoading`, `isError`, `error`, 和 `isSuccess` 等标志来向用户提供关于上传状态的实时反馈。这可以帮助提升用户体验,让用户了解当前正在发生的事情。
### 总结
通过组合使用 `react-query` 的 `useMutation` 钩子和 TypeScript,我们可以创建一个健壮且类型安全的文件上传功能。这种方法的好处是可以简化状态管理和错误处理,同时让代码更加清晰和易于维护。
阅读 7 · 8月23日 22:49
如何在react-query中的useQueries中使用自定义查询钩子
React Query 是一个强大的库,用于在 React 应用中处理服务端状态和缓存管理。它能够帮助开发者以一种高效和优雅的方式处理数据获取、缓存、同步和更新。`useQueries` 是 React Query 中的一个钩子,它允许批量并行执行多个查询。
自定义查询钩子(例如 `useCustomQuery`)通常是对 `useQuery` 或其他 React Query 钩子的封装,使其可以在不同的组件中重用查询的逻辑。
### 回答问题
在 `useQueries` 中使用自定义查询钩子的方法取决于你的自定义钩子是如何实现的。假设你有一个自定义钩子 `useCustomQuery`,它内部使用了 `useQuery` 钩子。为了让我们的讨论具体一些,假设我们的 `useCustomQuery` 钩子是用来获取用户数据的:
```javascript
import { useQuery } from 'react-query';
const useCustomQuery = (userId) => {
return useQuery(['user', userId], () => fetchUserById(userId));
};
const fetchUserById = async (userId) => {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
};
```
要在 `useQueries` 中使用这个钩子,我们需要稍作调整,因为 `useQueries` 接受的是一个查询对象数组,而不是直接调用钩子。我们可以创建一个函数,它返回这个对象,而不是直接使用 `useQuery`:
```javascript
const getCustomQueryObject = (userId) => ({
queryKey: ['user', userId],
queryFn: () => fetchUserById(userId)
});
```
然后,你可以在 `useQueries` 中使用这个函数来生成查询对象:
```javascript
import { useQueries } from 'react-query';
const userIds = [1, 2, 3]; // 假设这是我们要查询的用户 ID 列表
const userQueries = useQueries(
userIds.map(userId => getCustomQueryObject(userId))
);
```
### 实际应用案例
假设你在一个大型电商平台工作,需要在一个管理界面中同时显示多个用户的信息。使用 `useQueries` 和上述的自定义查询函数可以让你的代码更加清晰,更易于维护,同时提高页面的响应速度,因为所有用户数据的请求都是并行发出的。
### 总结
通过将自定义钩子中的查询逻辑抽象成返回查询对象的函数,我们可以灵活地在 `useQueries` 中重用这些逻辑。这样做既保持了代码的干净整洁,也便于在不同的场景下重用和扩展查询功能。
阅读 5 · 8月23日 22:48
如何使用React Hook Form自动保存进行React查询
在使用 React Hook Form 结合 React Query 进行数据处理和提交时,实现自动保存功能是一个常见的需求。接下来,我将详细介绍如何结合使用这两个库来实现自动保存的功能。
### 使用 React Hook Form 和 React Query 实现自动保存的步骤:
#### 1. 设置 React Hook Form
首先,我们需要设置 React Hook Form。我们将使用 `useForm` hook 来管理表单的状态和验证。
```jsx
import React from 'react';
import { useForm } from 'react-hook-form';
function FormComponent() {
const { register, handleSubmit, watch } = useForm();
// 其他逻辑
}
```
#### 2. 监听表单字段变化
为了实现自动保存,我们需要监控表单字段的变化。React Hook Form 的 `watch` 函数使我们能够监听一个或多个表单字段的变化。
```jsx
const formData = watch(); // 监听所有字段
```
#### 3. 使用 React Query 的 Mutation 进行数据保存
React Query 提供了 `useMutation` hook 来处理数据的异步更新。我们将使用它来发送更新请求。
```jsx
import { useMutation } from 'react-query';
const mutation = useMutation(newData => {
return axios.post('/api/data', newData);
});
```
#### 4. 实现表单的自动保存功能
接下来,我们结合 `watch` 和 `useMutation` 来实现自动保存。每当表单数据发生变化时,我们使用 `useEffect` hook 来触发保存操作。
```jsx
React.useEffect(() => {
const subscription = watch((value, { name, type }) => {
mutation.mutate(value);
});
return () => subscription.unsubscribe();
}, [watch, mutation]);
```
### 完整的组件示例
```jsx
import React from 'react';
import { useForm } from 'react-hook-form';
import { useMutation } from 'react-query';
import axios from 'axios';
function FormComponent() {
const { register, handleSubmit, watch } = useForm();
const mutation = useMutation(newData => {
return axios.post('/api/data', newData);
});
const formData = watch();
React.useEffect(() => {
const subscription = watch((value, { name, type }) => {
mutation.mutate(value);
});
return () => subscription.unsubscribe();
}, [watch, mutation]);
return (
<form>
<input name="username" ref={register} defaultValue="test" />
<input name="email" ref={register} defaultValue="test@example.com" />
<button type="submit">Submit</button>
</form>
);
}
```
### 总结
通过以上步骤,你可以实现一个具有自动保存功能的表单,在用户输入数据时,React Hook Form 会监控数据变化,并通过 React Query 的 mutation 自动触发数据保存。这种模式非常适合需要实时保存草稿或用户输入的场景。
阅读 7 · 8月23日 22:48
如何使用react查询突变在react中完成登录验证?
当使用React Query处理登录验证的突变(mutation)时,主要的步骤涉及设置一个用于执行登录操作的mutation,并处理响应以更新应用状态或进行错误处理。以下是如何实现的详细步骤:
### 1. 安装并引入React Query
首先,确保在你的项目中安装了React Query。
```bash
npm install react-query
```
在你的组件或服务文件中引入所需的React Query功能。
```javascript
import { useMutation } from 'react-query';
```
### 2. 创建登录函数
实现一个函数来处理API请求,这个函数将用户名和密码作为参数,并返回Promise。
```javascript
const loginUser = async (username, password) => {
const response = await fetch('/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password }),
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
};
```
### 3. 使用 `useMutation` 钩子
在你的组件中,使用 `useMutation` 钩子来管理登录过程。这个钩子允许你发送mutation,同时提供状态和错误处理的能力。
```javascript
function Login() {
const mutation = useMutation(({ username, password }) => loginUser(username, password), {
onSuccess: (data) => {
// 处理登录成功,例如保存token,跳转到另一个页面等
console.log('Login successful:', data);
},
onError: (error) => {
// 处理错误,例如显示错误消息
console.error('Login failed:', error);
},
});
const handleSubmit = (event) => {
event.preventDefault();
const username = event.target.elements.username.value;
const password = event.target.elements.password.value;
mutation.mutate({ username, password });
};
return (
<form onSubmit={handleSubmit}>
<input type="text" placeholder="Username" name="username" required />
<input type="password" placeholder="Password" name="password" required />
<button type="submit">Login</button>
{mutation.isLoading && <p>Loading...</p>}
{mutation.isError && <p>Error: {mutation.error.message}</p>}
{mutation.isSuccess && <p>Login Successful!</p>}
</form>
);
}
```
### 4. 错误处理和加载状态
React Query为mutation提供了多种状态标识,如`isLoading`, `isError`, `isSuccess`等,它们可以被用来在UI中展示相应的信息,如加载提示、错误消息或者成功状态。
### 实际例子
假设我们有一个登录表单,使用上述技术,我们不仅可以实现用户的登录并处理登录过程中可能出现的各种状态,还可以优化用户体验,例如在请求过程中显示加载状态,在遇到错误时给予明确反馈。
使用React Query的好处在于,它不仅管理异步逻辑的状态(如加载、错误和数据缓存等),还能通过其强大的配置选项和钩子,使开发者能够容易地实现更复杂的功能,如自动重试、数据依赖刷新等。
阅读 5 · 8月23日 22:47
React-query useQuery和 useMutation 之间有什么区别?
### useQuery 和 useMutation 的区别
React Query 是一个强大的库,用于在 React 应用中处理数据的获取、缓存、同步和更新。在 React Query 中,`useQuery` 和 `useMutation` 是两个非常核心的钩子(hooks),它们处理数据的方式和目标有所不同。
#### useQuery
**定义及用途:**
useQuery 主要用于异步获取数据,并将数据缓存在本地。当组件需要获取远程数据时,通常会使用 `useQuery`。它非常适合处理 GET 请求,来获取数据并展示。
**特点:**
- 自动缓存和更新数据。
- 提供数据状态管理,如 isLoading, isError, data 等。
- 支持数据的定时刷新和窗口聚焦刷新。
**例子:**
假设我们需要从一个 API 获取用户列表,我们可以这样使用 `useQuery`:
```javascript
const { data, error, isLoading } = useQuery('users', fetchUsers);
```
这里 `fetchUsers` 是一个异步函数,用来发送 GET 请求获取用户数据。
#### useMutation
**定义及用途:**
useMutation 用于执行修改数据的操作,如 POST, PUT, PATCH 或 DELETE 请求。这个 Hook 主要处理那些会对服务器数据造成更改的操作,并且这些操作通常不需要立即显示在 UI 上。
**特点:**
- 用于创建、更新或删除数据。
- 提供了 mutation 的状态管理,如 isLoading, isError, isSuccess。
- 支持回调函数,如 onSuccess, onError, onSettled,允许在操作完成后执行某些操作。
**例子:**
假设我们需要添加一个新用户,可以这样使用 `useMutation`:
```javascript
const mutation = useMutation(addUser, {
onSuccess: () => {
// 例如,添加成功后重新获取用户列表
queryClient.invalidateQueries('users')
}
});
// 调用 mutation
mutation.mutate({name: "新用户", age: 30});
```
这里 `addUser` 是一个发送 POST 请求的函数,用来创建新用户。
#### 总结
总的来说,`useQuery` 适用于获取并显示数据的场景,而 `useMutation` 适用于那些需要修改数据但不立即关心其显示的场景。使用这两个钩子能有效地管理数据状态和缓存,优化 React 应用的性能和用户体验。
阅读 6 · 8月23日 22:47
如何在react-query中重新获取集合的单个项
在React Query中,重新获取集合中的单个项可以通过几种不同的方式来实现,具体取决于你如何设置你的查询和你的数据依赖。下面我将详细解释两种常见的方法:
### 方法1:使用 `queryClient.invalidateQueries`
`react-query` 提供了一个 `queryClient` 实例,可以用来直接控制查询的状态。当你需要重新获取集合中的单个项时,你可以使用 `queryClient.invalidateQueries` 方法来使特定查询的缓存失效,从而触发重新获取。
假设我们有一个获取用户列表的查询,每个用户都有一个唯一的ID,现在我们需要更新特定用户的数据。
```jsx
import { useQuery, useQueryClient } from 'react-query';
function useUsers() {
return useQuery('users', fetchUsers);
}
function UserComponent({ userId }) {
const queryClient = useQueryClient();
const { data: users } = useUsers();
const refetchUser = async () => {
// 使特定用户的查询失效
await queryClient.invalidateQueries(['users', userId], {
refetchActive: true, // 重新获取处于 active 状态的查询
refetchInactive: false, // 不重新获取处于 inactive 状态的查询
});
};
return (
<div>
{users?.map(user => (
<div key={user.id}>{user.name}</div>
))}
<button onClick={refetchUser}>Refetch User</button>
</div>
);
}
```
在这个例子中,我们通过调用 `refetchUser` 函数来使特定用户的数据失效并重新获取。
### 方法2:使用 `queryClient.fetchQuery`
如果你需要更精确地控制重新获取的过程,或者如果你想要在不影响其他组件的情况下单独获取数据,你可以使用 `queryClient.fetchQuery`。
```jsx
function UserComponent({ userId }) {
const queryClient = useQueryClient();
const fetchUser = async () => {
const user = await queryClient.fetchQuery(['user', userId], () => fetchUserById(userId));
// 可选:更新查询缓存
queryClient.setQueryData(['user', userId], user);
};
return (
<button onClick={fetchUser}>Fetch User</button>
);
}
```
在这个例子中,`fetchUser` 函数直接从服务器获取最新的用户数据,并且可以选择性地更新查询缓存。
### 总结
这两种方法都可以有效地用于在React Query中重新获取集合的单个项。选择哪种方法取决于你的具体需求,比如是否需要立即反映在UI上,或者是否需要与其他数据查询解耦。在实际应用中,你可能需要根据具体情况调整数据获取和缓存更新的策略。
阅读 7 · 8月23日 22:41
如何传递过滤器变量以将InfiniteQuery与pageParam一起使用?
在React Query中,使用`InfiniteQuery`来实现无限滚动功能时,可能会遇到需要根据某些过滤条件(如用户输入或选择的标签)动态改变请求数据的情况。为了结合过滤器变量和`pageParam`,你可以按照以下步骤进行操作:
### 1. 定义初始过滤条件和查询函数
首先,你需要定义初始的过滤条件,并创建一个查询函数来根据这些条件和页码来获取数据。例如:
```javascript
import { useInfiniteQuery } from 'react-query';
function usePosts(filter) {
return useInfiniteQuery(
['posts', filter], // 使用数组来包含过滤条件和查询的key,确保过滤条件变化时可以重新获取数据
({ pageParam = 1 }) => fetchPosts(pageParam, filter),
{
getNextPageParam: (lastPage, pages) => lastPage.nextPage,
}
);
}
async function fetchPosts(page, filter) {
const response = await fetch(`/api/posts?page=${page}&filter=${filter}`);
return response.json();
}
```
### 2. 在组件中使用过滤器
接着,在你的组件中,根据用户的交互动态设置过滤条件,并将这些条件传递给上面定义的`usePosts`钩子。
```javascript
function PostsComponent() {
const [filter, setFilter] = useState('');
const handleFilterChange = (event) => {
setFilter(event.target.value);
};
const {
data,
error,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
status,
} = usePosts(filter);
return (
<>
<input type="text" value={filter} onChange={handleFilterChange} />
{data?.pages.map((page) =>
page.results.map((post) => <p key={post.id}>{post.title}</p>)
)}
<button onClick={() => fetchNextPage()} disabled={!hasNextPage || isFetchingNextPage}>
Load More
</button>
</>
);
}
```
### 3. 使用`useEffect`优化性能(可选)
如果你觉得数据更新太过频繁或者有性能问题,可以通过`useEffect`来延迟或限制请求的频率。
```javascript
useEffect(() => {
const handle = setTimeout(() => {
refetch(); // 可以调用来重新触发查询
}, 500); // 延迟500毫秒后触发
return () => clearTimeout(handle);
}, [filter, refetch]);
```
### 总结
这样,你就可以结合`InfiniteQuery`和动态的过滤条件来实现复杂的数据加载需求。在用户改变过滤条件时,`react-query`会自动重新发起请求以获取新的数据,并且保持页面状态和无限滚动的连贯性。
阅读 5 · 8月23日 22:31
如何输入useInfiniteQuery QueryFn的响应?
在使用 `useInfiniteQuery` 从 `react-query` 库中获取数据时,适当地为 QueryFn 响应类型建模非常关键。这样可以确保你的应用程序能够类型安全地处理数据,并且能更好地与 TypeScript 集成。
### 基本步骤:
1. **定义响应数据的类型**:
在 TypeScript 中,首先需要定义一个接口或类型,该接口或类型详细描述了 QueryFn 函数的预期响应结构。
2. **应用这个类型到 useInfiniteQuery**:
使用泛型参数将这个类型应用到 `useInfiniteQuery`,确保响应数据遵循定义的类型。
### 例子:
假设我们正在从一个 API 获取一串文章数据,每个文章对象包含 `id`, `title`, 和 `author` 属性。我们可以如下定义 TypeScript 接口:
```typescript
interface Article {
id: number;
title: string;
author: string;
}
interface ArticlesResponse {
page: number;
articles: Article[];
}
```
然后我们可以定义一个获取这些文章的异步函数,该函数接受当前页码作为参数:
```typescript
async function fetchArticles(pageParam: number): Promise<ArticlesResponse> {
const response = await fetch(`https://api.example.com/articles?page=${pageParam}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
}
```
最后,我们使用 `useInfiniteQuery` 并指定 `ArticlesResponse` 类型:
```typescript
import { useInfiniteQuery } from 'react-query';
function useInfiniteArticles() {
return useInfiniteQuery<ArticlesResponse, Error>({
queryKey: ['articles'],
queryFn: ({ pageParam = 1 }) => fetchArticles(pageParam),
getNextPageParam: (lastPage, allPages) => lastPage.page + 1
});
}
```
在这个例子中,我们清楚地定义了每个部分的类型,从 API 响应的数据结构(`ArticlesResponse`)到异步函数(`fetchArticles`)和最终的 `useInfiniteQuery` 调用。这样,你的代码不仅具有更好的可维护性,而且能够利用 TypeScript 提供的类型检查和自动补全功能,从而减少运行时错误。
阅读 5 · 8月23日 22:31