一、初始化项目
-
通过create-react-app命令创建项目,–template表示使用typescript(node版本高于14才能使用npx)
npx create-react-app jira --template typescript
-
配置绝对路径
在tsconfig.json中配置baseUrl,表示项目中的绝对路径是从src目录下开始寻找。
-
使用json-server来Mock数据
首先安装json-server:yarn add json-server -D
在根目录下创建_json_server_mock__文件夹,用来存放模拟的数据(名字可随意)
在package.json中配置scripts,新增json-server的命令:"json-server": "json-server __json_server_mock__/db.json --watch --port 3001"
由于json-server默认跑在3000的端口号上,和项目跑的端口号冲突,因此修改json-server的端口号为3001。
此时执行 npm run json-server
就可以启动json-server,进行数据的模拟。
-
配置api根路径
在根目录下创建 .env 和 .env.development文件, .env 是项目上线后使用的, .env .development是开发中使用的。在.env.development文件中添加:
REACT_APP_API_URL = http://localhost:3001
在项目中使用:
const apiUrl = process.env.REACT_APP_API_URL
二、JSX实现小demo
通过本demo的实现,可对React的状态提升、组件结合、数据传递和两个最基本hook有了一个完整的使用过程。
接口格式:
实现思路:可分成search_panel和list两个组件,在index中进行状态的保存,将状态通过props传递给search_panel和list两个组件使用。
const apiUrl = process.env.REACT_APP_API_URL;
export const ProjetcList = () => {
const [param, setParam] = useState({
name: '',
personalId: ''
})
const [list, setList] = useState([])
const [users, setUsers] = useState([])
useEffect(() => {
fetch(`${apiUrl}/projects?${qs.stringify(cleanObj(param))}`).then(async response => {
if(response.ok) {
setList(await response.json())
}
})
}, [param])
useEffect(() => {
fetch(`${apiUrl}/users`).then(async response => {
if(response.ok) {
setUsers(await response.json())
}
})
}, [])
return (
<div>
<SearchPanel users={users} param={param} setParam={setParam}/>
<List users={users} list={list}/>
</div>
)
}
注意:cleanObj方法用来处理param对象中值为空的情况,防止向服务端发送空参数。例如页面刚加载完,input为空,select也没有选中,此时param中的name和personId都是空的,在后端中就匹配不到这一项。
export const SearchPanel = ({users, param, setParam}) => {
return (
<form>
<div>
<input type="text" value={param.name} onChange={event => setParam({
...param,
name: event.target.value,
})} />
<select value={param.personId} onChange={event => setParam({
...param,
personId:event.target.value
})}>
<option value="">负责人</option>
{users.map(user => <option value={user.id} key={user.id}>{user.name}</option>)}
</select>
</div>
</form>
)
}
注意:{ ...param, name: event.target.value }
相当于Object.assign({}, params, name: event.target.value)
export const List = ({users, list}) => {
return(
<table>
<thead>
<tr>
<th>名称</th>
<th>负责人</th>
</tr>
</thead>
<tbody>
{
list.map(project => <tr key={project.id}>
<td>{project.name}</td>
<td>{users.find(user => user.id === project.personId)?.name || '未知'}</td>
</tr>)
}
</tbody>
</table>
)
}
注意:{users.find(user => user.id === project.personId)?.name || '未知'}
此处添加?
是因为users初始化的时候还是空数组,会出现undefined.name得情况,此时控制台会报错。加上?
就会将整句当成undefined,而不会报错,最终显示'未知'
。
接下来对demo进行优化处理:
初始化函数处理
在下拉框中,这个uers数组是不变的,只需要初始化的时候请求一下即可,因此useEffect第二个参数为空数组。
useEffect(() => {
fetch(`${apiUrl}/users`).then(async response => {
if(response.ok) {
setUsers(await response.json())
}
})
}, [])
但是如果页面中有很多需要进行初始化的函数,那么就会出现满屏都是useEffect(()=>{},[])
的情况,因此在这里对初始化的函数进行简单操作:
export const useMount = (callback) => {
useEffect(() => {
callback();
}, [])
}
调用的时候就是:
useMount(() => {
fetch(`${apiUrl}/users`).then(async response => {
if(response.ok) {
setUsers(await response.json())
}
})
})
咋一看和之前没多少变化,实则少了一个[]
!!!
防抖处理
在useEffect中,只要param改变,就会触发请求函数,这就导致input输入框中每次键盘按下,就会发起一次get请求,造成很大的性能浪费。
const debounce = (func, delay) => {
let timer;
return (...param) => {
if(timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
func(...param)
}, delay)
}
}
export const useDebounce = (value, delay) => {
const [ debouncedValue, setDebouncedValue ] = useState(value);
useEffect(() => {
const timer = setTimeout(() => { setDebouncedValue(value)}, delay)
return () => clearTimeout(timer)
}, [value, delay])
return debouncedValue;
}
这样一来,在输入间隔不超过delay毫秒的过程中,请求不会被触发,只有等到最后一个setTimeout执行完之后才会发送请求。在代码中使用:
const debouncedParam = useDebounce(param, 1000);
useEffect(() => {
fetch(`${apiUrl}/projects?${qs.stringify(cleanObj(debouncedParam))}`).then(async response => {
if(response.ok) {
setList(await response.json())
}
})
}, [debouncedParam])
接下来将该demo改为ts的语法格式,将所有文件后缀改成.tsx或.ts,在代码中使用interface定义参数的类型
export interface User {
id: number;
name: string;
}
interface SearchPanelProps {
users: User[],
param: {
name: string,
personId: string,
};
setParam: (param: SearchPanelProps['param']) => void;
}
export const SearchPanel = ({users, param, setParam}:SearchPanelProps) => {})
在index页面中,qs提示报错,这是因为当前下载的qs依赖中没有index.d.ts文件,该文件的作用就是对qs的js文件做了类型定义。命令行执行yarn add @types/qs -D
,安装后此处的报错就没有了。
interface Project {
id: number;
name: string;
personId: number;
pin: boolean;
organization: string;
}
interface ListProps {
users: User[],
list: Project []
}
export const List = ({users, list}: ListProps) => {
注意:在代码中可使用 // @ts-ignore
将ts告警忽略掉
三、登录
进行登录部分功能开发,首先编写基本代码:
export const LoginScreen = () => {
const handleSubmit = () => {
}
return <form onSubmit={handleSubmit}>
<div>
<label htmlFor="username">用户名</label>
<input type="text" id={'username'} />
</div>
<div>
<label htmlFor="password">密码</label>
<input type="password" id={'password'} />
</div>
<button type="submit">登录</button>
</form>
}
实现登录函数,点击登录后将username和password这两个参数传给服务端。
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
const username = (event.currentTarget.elements[0] as HTMLFormElement).value;
const password = (event.currentTarget.elements[1] as HTMLFormElement).value;
login({ username, password })
}
实现调用登录api的函数
const apiURL = process.env.REACT_APP_API_URL;
const login = (params: { username: string; password: string; }) => {
fetch(`${apiURL}/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(
async (response) => {
if(response.ok) {
}
}
)
}
由于json-server无法调用自定义api,这里使用middleware来配置json-server:
-
在__json_server_mock__文件夹下新建middleware.js文件,改文件包含nodejs代码,因此必须符合CommonJS规范。
-
在middleware.js中编写以下代码:
module.exports = (req, res, next) => {
if(req.method === 'POST' && req.path === '/login') {
if(req.body.username === 'jack' && req.body.password === '123456') {
return res.status(200).json({
user: {
token: '123'
}
})
} else {
return res.status(400).json({message: '用户名或密码错误'})
}
}
next()
}
-
最后将编写好的middleware注入到json-server中。在package.json中,给json-server后新增:--middlewares ./__json_server_mock__/middleware.js
命令
-
重启服务,输入正确的账号密码就能收到token
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)