PC端
安装指令:
npm create vite@latest react-ts-pro -- --template react-ts
Vite是一个框架无关的前端工具链,可以快速的生成一个React + TS的开发环境,并且可以提供快速的开发体验
说明:
1. npm create vite@latest固定写法(使用最新版本vite初始化项目)
2. react-ts-pro 项目名称(自定义)
3. -- --template react-ts 指定项目模板为react+ts
移动端(mobile)
1. 安装:
npm create vite@latest react-jike-mobile -- --template react-ts
2. 安装Ant Design Mobile
npm i --save antd-mobile
初始化路由(react-router-dom, 使用与我另一篇文章一模一样直接参考即可,ReactRouter使用详解(react-router-dom))
1. 安装
npm i react-router-dom
配置路径别名@(使用CRA可参考:cra(create-react-app)配置别名路径@ 以及Vscode联想路径配置)
1. 安装插件:
npm i @types/node -D
2. 修改vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// 配置别名路径,安装插件后才有path
import path from 'path' // 如果报错path可以写成import * as path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
// 配置别名路径
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
}
})
3. 修改tsconfig.json
{
"compilerOptions": {
// vscode联想配置
"baseUrl": "./",
"paths": {
"@/*": [
"src/*"
]
}
}
}
安装插件axios
npm i axios
http.ts封装代码如下:
// 封装axios
import axios from 'axios';
const httpInstance = axios.create({
baseURL: 'http://geek.itheima.net',
timeout: 5000
});
// 拦截器
httpInstance.interceptors.request.use(
config => {
return config
},
error => {
return Promise.reject(error)
}
)
httpInstance.interceptors.response.use(
response => {
return response
},
error => {
return Promise.reject(error)
}
)
export default httpInstance;
封装API模块-axios和ts的配合使用
场景:axios提供了request泛型方法,方便我们传入类型参数推导出接口返回值的类型
说明:泛型参数Type的类型决定了res.data的类型
具体演示代码如下:
import { http } from '@/utils';
// 假设后端返回的类型结构是这个
// {
// data: {
// channels: [
// {
// id: 1,
// name: ''
// }
// ]
// },
// nessage: ""
// }
/**
* channel列表查询
*/
// 1. 定义通用泛型(根据后端接口返回的数据来定义)
// data不是写死的,因此用通用的T(T代表泛型)
export type ResType<T> = {
message: string
data: T
}
// 2. 子项,定义具体特有的接口类型
type ChannelItem = {
id: number
name: string
}
// 整体类型:ChannelRes是data特有的类型
type ChannelRes = {
channels: ChannelItem[]
}
// 请求频道列表
export function fetchChannelAPI() {
http.request<ResType<ChannelRes>>({
url: '/channels'
})
}
/**
* 文章列表查询
*/
type ListItem = {
is_top: string,
cover: {
type: number
image: string[]
}
}
type ListRes = {
results: ListItem[]
pre_timestamp: string
}
// 传参类型
type ReqParams = {
channel_id: string
timestamp: string
}
export function fetchListAPI(params: ReqParams) {
return http.request<ResType<ListRes>>({
url: '/articles',
params
})
}
组件内使用代码如下:
方案一:
fetchChannelAPI().then(res => {
console.log(res.data)
})
方案二(建议写法):
useEffect(() => {
const getLists = async () => {
try {
const res = await fetchListAPI();
setLists(res.data);
} catch (error) {
throw new Error('fetch channel error')
}
}
getLists();
}, [])
ts基础数据渲染写法
import { useEffect, useState } from 'react';
import { fetchChannelAPI, ChannelItem } from '@/apis/user';
type ChannelItem = {
id: number
name: string
}
function Home() {
const [channels, setChannels] = useState<ChannelItem[]>([]);
useEffect(() => {
// const getChannels = async() => {
// try {
// const res = await fetchChannelAPI();
// setChannels(res.data);
// } catch (error) {
// throw new Error('fetch channel error')
// }
// }
// getChannels();
}, [])
return (
<div>
Home
</div>
)
}
export default Home;
ts基础数据渲染写法(自定义hook优化)
1. index.tsx代码如下:
import { useTabs } from './useTabs';
function Home() {
const {channels} = useTabs();
return (
<div>
Home
<ul>
{channels.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
</div>
)
}
export default Home;
// 抽离出业务部分封装成useTab
2. useTabs.tsx代码如下:
import { useEffect, useState } from 'react';
import { fetchChannelAPI, ChannelItem } from '@/apis/user';
function useTabs() {
const [channels, setChannels] = useState<ChannelItem[]>([]);
useEffect(() => {
const getChannels = async () => {
try {
const res = await fetchChannelAPI();
setChannels(res.data);
} catch (error) {
throw new Error('fetch channel error')
}
}
getChannels();
}, [])
return {
channels
}
}
export { useTabs };
详情模块 - 路由跳转
1. Home组件代码如下:
// import { useTabs } from './useTabs';
import { useNavigate } from "react-router-dom";
function Home() {
// const {channels} = useTabs();
const navigate = useNavigate();
const goDetail = () => {
navigate('/detail?id=159')
}
return (
<div>
Home
{/* <ul>
{channels.map(item => <li key={item.id}>{item.name}</li>)}
</ul> */}
<hr />
<button onClick={goDetail}>Detail</button>
</div>
)
}
export default Home;
2. Detail组件代码如下:
import { useEffect } from "react";
import { useSearchParams } from "react-router-dom";
function Detail() {
const [params] = useSearchParams();
useEffect(() => {
const id = params.get('id');
console.log(id);
}, [])
return (
<div>
Detail
</div>
)
}
export default Detail;