开始搭建
检查node版本
创建名为project-react的项目
npx create-react-app project-react
创建成功
创建项目src目录
下载第三方包(自己进行测试)
//scss预处理器
npm install sass -D
//Ant Design(https://3x.ant.design/docs/react/introduce-cn)
npm install antd --save
下载路由包并进行测试
npm install react-router-dom
在pages
目录下创建Layout
和 Login
文件夹,并输入测试代码
export default function index() {
return (
<div>
this is Login(Layout)
</div>
)
}
在router
目录下的index.js
中进行配置
import React from "react";
import { createBrowserRouter } from "react-router-dom";
import Layout from "../pages/Layout";
import Login from "../pages/Login";
const router = createBrowserRouter([
{
path:'/',
element:<Layout/>
},
{
path:'/login',
element:<Login/>
}
])
export default router
在index.js
进行配置
import { RouterProvider } from 'react-router';
import router from './router'
root.render(
<React.StrictMode>
<RouterProvider router={router}/>
</React.StrictMode>
);
配置@路径简化路径处理
yarn add -D @craco/craco
在项目根目录中创建 craco
的配置文件
//craco.config.js
const path = require('path')
module.exports = {
webpack: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
}
并在package.json
中进行修改
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
}
在项目根目录中创建jsconfig.json
文件
//自动提示路劲
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
}
}
登录页搭建
login/index.js
//assets文件内引入login.png背景图片helogo.png图片
import { Card, Form, Input, Button, Checkbox } from 'antd'
import logo from '@/assets/logo.png'
import './index.scss'
const Login = () => {
const onFinish=(value)=>{
console.log(value);
}
return (
<div className="login">
<Card className="login-container">
<img className="login-logo" src={logo} alt="" />
<Form onFinish={onFinish} validateTrigger={['onBlur', 'onChange']}>
<Form.Item
name="mobile"
rules={[
{
pattern: /^1[3-9]\d{9}$/,
message: '手机号码格式不对',
validateTrigger: 'onBlur'
},
{ required: true, message: '请输入手机号' }
]}
>
<Input size="large" placeholder="请输入手机号" />
</Form.Item>
<Form.Item
name="code"
rules={[
{ len: 6, message: '验证码6个字符', validateTrigger: 'onBlur' },
{ required: true, message: '请输入验证码' }
]}
>
<Input size="large" placeholder="请输入验证码" maxLength={6} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" size="large" block>
登录
</Button>
</Form.Item>
</Form>
</Card>
</div>
)
}
export default Login
封装请求模块
npm i axios
在utils
目录下新建request.js
文件.
import axios from 'axios'
const request = axios.create({
baseURL: URL,
timeout: 5000
})
// 添加请求拦截器
request.interceptors.request.use((config)=> {
return config
}, (error)=> {
return Promise.reject(error)
})
// 添加响应拦截器
request.interceptors.response.use((response)=> {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response
}, (error)=> {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error)
})
export { request }
在utils
目录下新建idnex.js
文件,进行统一导出
import { request } from "./request";
export {
request
}
使用redux对token进行管理
npm i react-redux @reduxjs/toolkit
在store
目录下新建index.js
和modules/user.js
modules下的js
文件是对项目进行模块化。
//modules/user.js
import { request } from "@/utils"
import { createSlice } from "@reduxjs/toolkit"
const userStore = createSlice({
name: 'user',
initialState: {
token: ''
},
reducers: {
setToken(state, actions) {
state.token = actions.payload
}
}
})
const { setToken } = userStore.actions
const userReducer = userStore.reducer
const fetchLogin = (loginForm) => {
return async (dispatch) => {
const res = await request.post('/authorizations', loginForm)
dispatch(setToken(res.data.data.token))
}
}
export { fetchLogin, setToken }
export default userReducer
index.js
文件是对模块化的组件进行统一的管理
//index.js
import { configureStore } from "@reduxjs/toolkit"
import userReducer from './modules/user'
export default configureStore({
reducer: {
user: userReducer
}
})
再导入根目录下的index.js
中。进行配置
import { Provider } from 'react-redux';
import store from './store';
root.render(
<React.StrictMode>
<Provider store={store}>
<RouterProvider router={router}/>
</Provider>
</React.StrictMode>
);
在登录页发送请求并调用
import { useDispatch } from 'react-redux'
import { fetchLogin } from '@/store/modules/user'
import { useNavigate } from 'react-router-dom'
const dispatch = useDispatch()
const navigate = useNavigate()
//在表单上面绑定onFinsh提交方法
const onFinish = async (value) => {
//这里的async和await是确保方法调用成功时后面的跳转功能才会触发
await dispatch(fetchLogin(value))
navigate("/")
message.success('登录成功')
}
token持久化
对本地存储的方法进行封装,创建 utils/token.js
文件
const TOKENKEY= 'token_key'
function setToken(token){
window.localStorage.setItem(TOKENKEY, token)
}
function getToken(){
return window.localStorage.getItem(TOKENKEY)
}
function removeToken(){
window.localStorage.removeItem(TOKENKEY)
}
export {
setToken,
getToken,
removeToken
}
在utils/index.js
中进行导入
import {setToken, getToken, removeToken} from './token'
export { setToken , getToken , removeToken }
在store/modules/user.js
中进行应用
import { setToken as _setToken, getToken } from "@/utils"
const userStore = createSlice({
name: 'user',
initialState: {
token: getToken() || ''
},
reducers: {
setToken(state, actions) {
state.token = actions.payload
_setToken(actions.payload)
}
}
})
路由权限控制
在 components
目录中,创建 AuthRoute/index.js
文件
import { getToken } from '@/utils'
import { Navigate } from 'react-router-dom'
function AuthRoute ({ children }) {
const isToken = getToken()
if (isToken) {
return <>{children}</>
} else {
return <Navigate to="/login" replace />
}
}
export { AuthRoute }
在index.js
里面进行配置
import { AuthRoute } from "@/components/AuthRoute";
const router = createBrowserRouter([
{
path: '/',
element: <AuthRoute> <Layout /></AuthRoute>
},
])
export default router