React 实战 Todolist (上)

写在前面

最近在学 react ,所以就顺手写一个 Todolist 作为练手项目。
github 地址 : ReactMall

1. 项目初始化

1.1 项目的创建

可以直接用 webstorm 直接 create
在这里插入图片描述
这样就ok了!
在这里插入图片描述

1.2 配置less

由于react配置less没有像vue那种那么方便,所以我们需要执行下面这个来进行配置

yarn eject

在这里插入图片描述

完成之后我们就会出现这个配置文件夹,然后我们用 webpack.config.js 这个文件进行操作

在这里插入图片描述
我们搜索 sassModuleRegex ,然后我们在大概 528 行左右的位置插入以下的片段。

{
    
    
    test: /\.less$/,
    use :getStyleLoaders({
    
    

    },'less-loader')
},

在这里插入图片描述
这样我们的less才算配置好!

然后我们再创建几个文件夹作为目录入口

在这里插入图片描述

1.3 配置路由

因为我们的 login、register 是类似的功能的,所以就放在了同层级路由上面。

然后 list 我们就放在主页下面吧,其实直接用主页面也行,但是为了路由规范一点,让我们知道这个路由下的功能是啥,就还是 list 了。

import App from "../App";
import Login from "../pages/Login";
import Register from "../pages/Register";
import {
    
    BrowserRouter as Router,Routes,Route} from 'react-router-dom'
import List from "../pages/List";

const BaseRouter = () => (
    <Router>
        <Routes>
            <Route path='/' element={
    
    <App />}>
                <Route path='/list' element={
    
    <List/>}></Route>
            </Route>
            <Route path='/login' element={
    
    <Login/>}></Route>
            <Route path='/register' element={
    
    <Register/>}></Route>
        </Routes>
    </Router>
)

export default BaseRouter

1.4 pages的创建

在 List.jsx、Login.jsx、Register.jsx 直接放上一些模版代码。先代替一下,检测看看能不能渲染出来,后续再进行替换。

import React from 'react';

function Register() {
    
    
    return (
        <div>
            Register
        </div>
    )
}

export default Register;

在这里插入图片描述

2. 项目开发

2.1 api请求

这一层我们是做request请求使用,用于请求后台的数据。

再src下新建一个request文件夹用来放 api 接口等等…
在这里插入图片描述
然后创建 request.js 文件

如果没有axios的话,记得提前 yarn add axios

import axios from 'axios'

// 配置项
const axiosOption = {
    
    
    baseURL: 'http://localhost:4000/api/v1',
    timeout: 5000
}

// 创建一个单例
const instance = axios.create(axiosOption);

// 添加请求拦截器
instance.interceptors.request.use(function (config){
    
    
    let token = localStorage.getItem('token')

    if (token){
    
    
        config.headers={
    
    
            'Authorization':token
        }
    }

    return config;
}, function (error){
    
    
    // 对请求错误做些什么
    return Promise.reject(error);
})

// 添加相应拦截器
instance.interceptors.response.use(function (response){
    
    
    // 对响应头的数据做处理
    return response.data;
}, function (error){
    
    
    return Promise.reject(error)
});

export default instance;

2.2 注册与登陆页面

  • src/request/api.js

这是两个后台的接口,分别是登陆和注册。

export const RegisterApi =(params)=> request.post('/user/register',params)
export const LoginApi =(params)=> request.post('/user/login',params)
  • src/pages/Login.jsx

请求后台数据

const onFinish = (values) => {
    
    
        LoginApi({
    
    
            user_name: values.username,
            password: values.password
        }).then(res => {
    
    
            console.log(res)
            if(res.status===200){
    
    
                localStorage.setItem("token",res.data.token);
                localStorage.setItem("user_name",res.data.user.user_name);
                localStorage.setItem("avatar","https://q1.qlogo.cn/g?b=qq&nk=3274661196&s=640")
                message.success("登陆成功").then();
                // 跳到登录页
                setTimeout(()=>{
    
    
                    navigate('/list')
                } ,800)
            }else{
    
    
                message.error(res.msg).then();
            }
        })
    };

主体是一个 from 表单 对数据进行调试

<Form
    name="basic"
    initialValues={
    
    {
    
    
        remember: true,
    }}
    onFinish={
    
    onFinish}
    autoComplete="off"
>
    <Form.Item
        name="username"
        rules={
    
    [
            {
    
    
                required: true,
                message: '请输入用户名!',
            },
        ]}
    >
    <Input size='large' prefix={
    
    <UserOutlined className="site-form-item-icon" />} placeholder="请输入用户名"/>
</Form.Item>

<Form.Item
    name="password"
    rules={
    
    [
        {
    
    
            required: true,
            message: '请输入密码!',
        },
    ]}
>
   <Input.Password size='large' prefix={
    
    <LockOutlined className="site-form-item-icon" />} placeholder="请输入密码"/>
</Form.Item>

<Form.Item>
   <Link style={
    
    {
    
    
       float: 'right',
   }} to="/register">还没账号?立即注册</Link>
</Form.Item>

<Form.Item>
   <Button size='large' type="primary" htmlType="submit" block>
       登陆
   </Button>
</Form.Item>
</Form>

登陆页面就像这个样子
在这里插入图片描述

2.3 主页面

先看页面样子

在这里插入图片描述
我们看到这个页面分成了上中下三个部分,最伤面的状态栏,最下面的脚注信息,中间的主体信息。

2.3.1 顶部header

顶部的 header 我们可以抽离一个 component 出来。就叫 Header.jsx
在这里插入图片描述
而header的信息是用户的头像和名字,我们可以从 localstory 中选取,并且使用 useEffect 进行初始化。

const [avatar,setAvatar]=useState('')
    const [userName,setUserName]=useState("")
    const navigate = useNavigate();

    useEffect(()=>{
    
    
        let username1 = localStorage.getItem('user_name')
        let avatar1 = localStorage.getItem('avatar')
        if(username1){
    
    
            setUserName(username1)
        }
        if(avatar1){
    
    
            setAvatar(avatar1)
        }
    },[]);

2.3.2 底部部分

底部我们不需要展示什么信息,所以可以简单一点嵌入到app中即可,但也可以抽离成组件,方便后续的扩展。

function App() {
    
    
  return (
      <Layout id='app'>
          <Header />
          <div className='container'>
            <div className='container_box'>
            <div className="container_content">
              <Outlet />
            </div>
          </div>
        </div>
        <Footer className='footer_content'>TodoList | Copyright &copy; 2023 Author FanOne</Footer>
      </Layout>
  )
}

还有一个中间部分的,由于涉及到了组件之间的传递,我们下一遍博客再讲解。
所有的代码都在github上:https://github.com/CocaineCong/react-mall

猜你喜欢

转载自blog.csdn.net/weixin_45304503/article/details/128677904