前后端分离实践:使用 React 和 Express 搭建完整登录注册流程

文章目录

概要

本项目是一个基于React和Express的简单登录注册系统。通过前后端分离的方式,实现了用户的注册、登录和查看用户列表等功能。前端使用React框架构建了用户界面,后端使用Express框架处理用户请求。借助`Ant Design组件库,我们不仅实现了基本的用户认证功能,还为用户提供了友好的界面体验。

整体架构流程

  1. 用户在Ant Design组件库提供的UI组件组成的前端界面输入邮箱和密码进行登录或注册操作。
  2. 前端通过React Router实现页面导航,通过axios库将用户输入的数据发送HTTP请求至后端。
  3. 后端Express服务器接收到请求后,根据路由管理不同请求,通过Controller层处理业务逻辑,并与数据库进行数据交互。
  4. 对于登录请求,后端查询数据库验证用户信息,返回登录成功或失败的响应。
  5. 对于注册请求,后端将新用户信息插入数据库,并返回注册成功或失败的响应。
  6. 对于查看用户列表的请求,后端从数据库中获取所有用户信息,并将其返回给前端。
  7. 前端接收到后端返回的数据后,根据需要更新界面展示用户列表或处理其他业务。

技术名词解释

React

React是一个用于构建用户界面的JavaScript库,它提供了组件化开发的思想和一系列工具,使得构建复杂用户界面更加简单和可维护。

Express

Express是一个基于Node.js的Web应用开发框架,它提供了一系列的功能和工具,使得构建高性能、可扩展的Web应用变得更加容易。

React Router

React Router是React的官方路由库,用于管理应用的路由和页面导航,使得构建单页面应用更加简单和灵活。

Ant Design

一套基于React的企业级UI组件库,提供了丰富的UI组件和设计模式,帮助开发者快速构建美观的用户界面。

技术细节

前端设计

使用React框架构建了登录注册页面,并采用Ant Design组件库提供的Input、Button等组件,使得界面清晰易用。

首先构建一个基础的react APP名字为react-study

shell 复制代码
npx create-react-app react-study

src目录下新建一个components文件夹,里面存放各个组件,例如登录注册,用户列表等

导入整体布局layout.js,如下图所示:


登录Login.js

javascript 复制代码
import React from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { Form, Input, Button,message } from 'antd';
import axios from 'axios';


const Login = () => {
  const navigate = useNavigate();

  const onFinish = (n) => {
    console.log(n.email);
    console.log(n.password);
    axios({
      method: 'post',
      url: 'http://localhost:2531/login',
      data: {
        email: n.email,
        password: n.password
      }
    }).then((res) => {
      if (res.data.success) {
        message.success('登陆成功');
        // console.log(`Object ${res.data}`);
        console.log(res.data);
        navigate('/users')
      } else {
        message.success('用户名或密码不正确');
        console.log(res.data);
      }
    }).catch(() => {
      console.log("Something went wrong. Plase try again later");
    });
  };

  return (
    <div className="login1">
    <Form
      name="normal_login"
      labelCol={{
        span: 8,
      }}
      wrapperCol={{
        span: 16,
      }}
      style={{
        maxWidth: 600,
      }}
      className="login-form"
      initialValues={{ remember: true }}
      onFinish={onFinish}
    >
      <Form.Item
        name="email"
        label="邮箱"
        rules={[{ required: true, message: '请输入邮箱!' }]}
      >
        <Input placeholder="邮箱" 
        />
      </Form.Item>

      <Form.Item
        name="password"
        label="密码"
        rules={[{ required: true, message: '请输入密码!' }]}
      >
        <Input.Password
          placeholder="密码"
        />
      </Form.Item>

      <Form.Item
       wrapperCol={{
        offset: 8,
        span: 16,
       }}
      >
        <Button type="primary" htmlType="submit" className="login-form-button">
          登录
        </Button>
        <span className="zhuce">
            <Link to="/register">没有账号?去注册吧!</Link>
        </span>
      </Form.Item>
    </Form>
    </div>
  );
};

export default Login;

注册Register.js

javascript 复制代码
import React from 'react';
import "./Login.css"
import { useNavigate } from 'react-router-dom';
import { Form, Checkbox, Input, Button, message } from 'antd';
// import { LockOutlined } from '@ant-design/icons';
import axios from 'axios';

const tailFormItemLayout = {
  wrapperCol: {
    xs: {
      span: 24,
      offset: 0,
    },
    sm: {
      span: 16,
      offset: 8,
    },
  },
};

const Register = () => {
  // const [email, setEmail] = useState('');
  // const [password, setPassword] = useState('');
  const navigate = useNavigate();

  const onFinish = (n) => {
    axios({
      method: 'post',
      url: 'http://127.0.0.1:2531/register',
      data: {
        email: n.email,
        password: n.password
      }
    }).then((res) => {
      if (res.data.success) {
        message.success('注册成功');
        console.log(res.data);
        navigate('/login')
      } else {
        message.success('注册失败');
        console.log(res.data);
      }
    }).catch(() => {
      console.log("Something went wrong. Plase try again later");
    });
  };

  return (
    <div className="login1">
    <Form
      name="normal_register"
      labelCol={{
        span: 8,
      }}
      wrapperCol={{
        span: 16,
      }}
      style={{
        maxWidth: 600,
      }}
      className="register-form"
      initialValues={{ remember: true }}
      onFinish={onFinish}
    >

      {/* 邮箱 */}
      <Form.Item
        name="email"
        label="邮箱"
        rules={[{ required: true, message: '请输入邮箱!' }]}
      >
        <Input 
        placeholder="邮箱"
        // value={email}
        // onChange={(e) => setEmail(e.target.value)}
        />
      </Form.Item>


      {/* 密码 */}
      <Form.Item
        name="password"
        label="密码"
        rules={[{ required: true, message: '请输入密码!' }]}
        hasFeedback
      >
        <Input.Password
          placeholder="密码"
          // value={password} 
          // onChange={(e) => setPassword(e.target.value)}
        />
      </Form.Item>

      {/* 重新输入密码 */}
      <Form.Item
          name="confirm1"
          label="验证密码"
          dependencies={['password']}
          hasFeedback
          rules={[
            {
              required: true,
              message: '请再一次填入密码!',
            },
            ({ getFieldValue }) => ({
              validator(_, value) {
                if (!value || getFieldValue('password') === value) {
                  return Promise.resolve();
                }
                return Promise.reject(new Error('两次密码不符!'));
              },
            }),
          ]}
        >
          <Input.Password 
          placeholder="重新输入密码"
          />
        </Form.Item>


        {/* 接受同意 */}
        <Form.Item
          name="agreement"
          valuePropName="checked"
          rules={[
            {
              validator: (_, value) =>
                value ? Promise.resolve() : Promise.reject(new Error('Should accept agreement')),
            },
          ]}
          {...tailFormItemLayout}
        >
          <Checkbox>
            I have read the <span>agreement</span>
          </Checkbox>
        </Form.Item>

      {/* 注册按钮 */}
      <Form.Item {...tailFormItemLayout}>
        <Button type="primary" htmlType="submit" className="register-form-button">
          注册
        </Button>
      </Form.Item>
    </Form>
    </div>
  );
};

export default Register;

用户列表UserList.js

javascript 复制代码
import React, { useState, useEffect } from "react";
import axios from 'axios';

const UserList = () => {
    const [users, setUsers] = useState([]);
    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await axios.get('http://localhost:2531/users');
                setUsers(response.data);
            } catch (error) {
                console.error(error);
            }
        };
        fetchData();
    }, []);

    return (
        <div>
            <h1>用户列表</h1>
            <ul>
                {users.map(user => (
                    <li key={user.id}>{user.email}</li>
                ))}
            </ul>
        </div>
    )
}

export default UserList;

然后里面的组件都放在routes.js里面,使用 react-router-dom 实现路由功能,然后在 App.js 中引入 routes.js

后端逻辑

后端通过Express框架处理了登录、注册和用户列表展示等请求,并利用Controller层来处理业务逻辑,从数据库中读取和存储用户信息。

在 react-study目录下创建server目录,在这个文件夹下创建db.js封装连接数据库的操作

在控制器controller.js里封装数据库的操作,查询user表的所有信息,插入数据,根据邮箱和密码查询数据

用路由POST挂载提交登录和注册的操作,GET得到所有列表

app.js里挂载路由的方法,用跨域访问不同的端口,npm run server启动服务

数据交互

前端通过axios库发送HTTP请求与后端通信,后端接收请求后进行相应的业务处理,并将处理结果返回给前端。

在react前端提交表单的时候,onFinish函数可以用axios库去提交login的请求,注册和登录的方法是相同的

获取用户列表也可以用axios库去得到数据库里的数据

小结

通过本项目的实践,我们深入了解了React、Express和Ant Design这些流行的前端和后端技术。通过将它们结合起来,我们成功构建了一个简单而完整的登录注册系统,为今后开发更复杂的应用奠定了基础。

相关推荐
飞天狗19 分钟前
长列表滚动卡顿怎么破:虚拟列表选型 + react-virtuoso 实战调优指南
react.js·性能优化
binbin_523 小时前
React 井字棋教程:用一个小游戏理解组件和状态
前端·react.js·前端框架
张元清4 小时前
React useObjectUrl Hook:预览文件与 Blob,不留内存泄漏(2026)
javascript·react.js
真的想不出名儿7 小时前
Md编辑器整合-react
前端·react.js·编辑器
牛仔只喝牛奶1 天前
多端跨端技术选型:小程序 + H5 + App 的两栈拆分落地
react native·react.js
wear工程师1 天前
setState 到底是不是异步的?这题从 React 16 问到 18,标准答案早就变了
react.js·面试
wanghowie1 天前
LangGraph4j 落地(二)— ReAct 多步工具与 trace 扩展
前端·react.js·前端框架
csj501 天前
前端基础之《React(11)—state声明式》
前端·react.js
张元清1 天前
React useLocalStorage Hook:SSR 安全的持久化状态(2026)
javascript·react.js
析数塔1 天前
2026前端框架深度解析:React Compiler、Angular Zoneless、Vue 3.5重写游戏规则
前端·vue.js·react.js