当前位置: 首页 > article >正文

从零开始用react + tailwindcss + express + mongodb实现一个聊天程序(四) 实现注册功能

1.前端页面文件夹  路由功能 

  前端web目录下 创建pages 文件夹 创建Home.jsx   首页  SignUpPage 注册 LoginPage 登录 

  ProfilePage 个人资料  SettingPage

 各个页面简单实现一下 内容如下

const HomePage = () => {
    return (
      <div>
          HomePage
      </div>
    )
  }
  
  export default HomePage

 在main.js 引入  BrowserRouter

import { BrowserRouter } from 'react-router-dom' 

用BrowserRouter 把App 组件包裹 提供给全局路由功能

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'

import { BrowserRouter } from 'react-router-dom'
createRoot(document.getElementById('root')).render(
  <StrictMode>
    <BrowserRouter>
        <App />
    </BrowserRouter>
  </StrictMode>,
)

 App.jsx 内容  如下  


import HomePage from '@/pages/HomePage'
import SignUpPage from './pages/SignUpPage'
import ProfilePage from './pages/ProfilePage'
import LoginPage from './pages/LoginPage'
import SettingsPage from './pages/SettingPage'

import { Routes, Route} from 'react-router-dom'
const App = () => {
  return (
    <div>
      <Routes>
        <Route path="/" element={<HomePage />} /> 
        <Route path="/signup" element={<SignUpPage />} /> 
        <Route path="/login" element={<LoginPage /> } /> 
        <Route path="/settings" element={<SettingsPage /> } /> 
        <Route path="/profile" element={<ProfilePage />} /> 
      </Routes>
    </div>
  )
}

export default App

  1.测试 路由功能  首页跳转到注册 再从注册跳转到首页

 HomePage.jsx 内容如下


import {Link} from "react-router-dom"
const HomePage = () => {
    return (
      <div>
          <p className="text-red-500">首页</p>
          <Link to="/signup">跳转注册页面</Link>
      </div>
    )
  }
  
  export default HomePage

注册页面类似 点击跳转可以实现路由切换  

 

2.注册页面

 注册页面分2部分 我们先实现左侧功能 

import { useState } from "react";
import { MessageSquare,User,Mail,Lock,Eye, EyeOff,Loader2} from "lucide-react";
import {Link} from "react-router-dom"

    const SignUpPage = () => {
    const [showPassword, setShowPassword] = useState(false);
    const [formData, setFormData] = useState({
        userName: "",
        email: "",
        password: "",
    })
    const {signup,isSigningUp} = useAuthStore();

    const validateForm = () => {
        
    }

    const handleSubmit = (e) => {
        console.log(e)
        e.preventDefault();
    }

  return (
    <div className="min-h-screen grid lg:grid-cols-2">
       {/*left side*/}
        <div className="flex flex-col justify-center items-center p-6 sm:p-12">
            <div className="w-full mt-10">
                {/* logo */}
                <div className="text-center mb-8">
                    <div className="flex flex-col items-center gap-2 group">
                        <div className="size-12 rounded-xl bg-primary/10 flex items-center justify-center
                        group-hover:bg-primary/20 transition-colors">
                            <MessageSquare className="size-6 text-primary"></MessageSquare>
                        </div>
                        <h1 className="text-2xl font-bold mt-2">账号注册</h1>
                        <p className="text-base-content/60">从免费创建账号开始</p>
                    </div>
                </div>
                {/* form */}
                <form onSubmit={handleSubmit} className="space-y-6">
                    <div className="form-control">
                        <label className="label">
                            <span className="label-text font-medium">用户名</span>
                        </label>
                        {/* 输入框 */}
                        <div className="relative">
                            <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                                <User className="size-5 text-base-content/40" />
                            </div>
                            <input 
                                type="text"
                                className={`input input-bordered w-full pl-10`}
                                placeholder="请输入用户名"
                                value={formData.userName}
                                onChange={(e)=> setFormData({...formData,userName:e.target.value})}
                            >

                            </input>
                        </div>
                    </div>
                    <div className="form-control">
                        <label className="label">
                            <span className="label-text font-medium">邮箱</span>
                        </label>
                        {/* 输入框 */}
                        <div className="relative">
                            <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                                <Mail className="size-5 text-base-content/40" />
                            </div>
                            <input 
                                type="text"
                                className={`input input-bordered w-full pl-10`}
                                placeholder="请输入邮箱地址"
                                value={formData.email}
                                onChange={(e)=> setFormData({...formData,email:e.target.value})}
                            >

                            </input>
                        </div>
                    </div>

                    <div className="form-control">
                        <label className="label">
                            <span className="label-text font-medium">密码</span>
                        </label>
                        {/* 输入框 */}
                        <div className="relative">
                            <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                                <Lock className="size-5 text-base-content/40" />
                            </div>
                            <input 
                                type={showPassword ? "text" : "password"}
                                className={`input input-bordered w-full pl-10`}
                                placeholder="请输入密码"
                                value={formData.password}
                                onChange={(e)=> setFormData({...formData,password:e.target.value})}
                            >
                            </input>
                            
                            <button
                                type="button"
                                className="absolute inset-y-0 right-0 pr-3 flex items-center"
                                onClick={()=> setShowPassword(!showPassword)}
                            >
                                {showPassword ? (<EyeOff className="size-5 text-base-content/40" />) : (<Eye className="size-5 text-base-content/40" />)}
                            </button>
                        </div>
                    </div>

                   <button 
                        type="submit"
                        className="btn btn-primary w-full"
                        disabled={isSigningUp}
                    >

                        {isSigningUp ? (
                            <>
                                <Loader2 className="size-5 animate-spin"/>
                                Loading...
                            </>
                        ):(
                            "创建账户"
                        )}
                    </button>
                </form>

                <div className="text-center">
                    <p className="text-base-content/60">
                        已有账号?{""}
                        <Link to="/login" className="link link-primary">去登录</Link>
                    </p>
                </div>
            </div>
        </div>

        {/* right side */}
    </div>
  )
}

export default SignUpPage

效果

  1.引入axios 

        前端http请求 我们通axios实现  新建lib文件夹 创建axios.js

import axios from 'axios';

const axiosInstance = axios.create({
    baseURL: 'http://localhost:3000/api',  //后端服务地址
    withCredentials: true,
})

export default axiosInstance;

  2.引入zustand 

     我们全局所有接口请求 状态 数据都用zustand管理 类似 pinia vuex redux等

  新建store文件夹 创建userAuthStore.js   主要实现用户登录 注册 认证功能

import {create} from 'zustand'
import axiosInstance from '../lib/axios'
import toast from 'react-hot-toast'

// 创建一个auth store
export const useAuthStore = create((set,get) => ({
    authUser:null, // 用户信息
    isSigningUp: false, // 是否登录
    isLoginningIn: false, // 是否登录中

    signup: async(data) => {
        set({isSigningUp: true})
        try {
            const res = await axiosInstance.post('/auth/signup', data)
            toast.success("注册成功")
            set({authUser: res.data})
        } catch (error) {
            console.log("useAuthStore signup error",error.message)
            set({isSigningUp: true})
        } finally {
            set({isSigningUp: false})
        }
    },
    login: async(data) => {
        set({isLoginningIn: true})
        try {
            const res = await axiosInstance.post('/auth/login', data)
            set({authUser: res.data})
            toast.success("登录成功")

        } catch (error) {
            toast.error(error.response.data.message)
        } finally{
            set({isLoginningIn: false})
        }
    },
    logout: async() => {
        try {
            await axiosInstance.post('/auth/logout')
            set({authUser: null})
            toast.success("退出成功")
        } catch (error) {
            console.log("useAuthStore logout error",error.message)
        }
    }
}))

在signupPage 引入useAuthStore 更新如下代码 

const {signup,isSigningUp} = useAuthStore();

    const validateForm = () => {
        if(!formData.userName.trim()) return toast.error("请输入用户名");
        // 邮箱正则验证
        if(!/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(formData.email)) return toast.error("请输入正确的邮箱");
        if(formData.password.length < 6) return toast.error("请输入至少6位的密码");

        return true
    }

    const handleSubmit = (e) => {
        console.log(e)
        e.preventDefault();
        const success = validateForm();
        if(success) signup(formData);
    }

注册按钮加个loading的状态 

<button 
                        type="submit"
                        className="btn btn-primary w-full"
                        disabled={isSigningUp}
                    >

                        {isSigningUp ? (
                            <>
                                <Loader2 className="size-5 animate-spin"/>
                                Loading...
                            </>
                        ):(
                            "创建账户"
                        )}
                    </button>

3.测试注册功能

看提示根据浏览器同源策略  前后端端口不一样 跨域了

所以我们要去server端配置下跨域 配置很简单

在server index.js中引入cors  做如下配置

import cors from 'cors'

// 跨域配置

// app.options('*', cors()) // include before other routes

app.use(cors({

    origin:'http://localhost:5173', // 我们前端的地址

    credentials: true

  }))

然后再去前端发送注册请求 

提示注册成功!!

去数据库验证结果 也有我们刚注册的用户

这篇 就这样把 不写登录功能了 篇幅有点多 有问题欢迎评论留言!!喜欢的来个3连 谢谢!! 


http://www.kler.cn/a/563235.html

相关文章:

  • 基于Matlab的语音识别系统设计
  • nginx基础篇 - 什么是代理服务器?正向代理和反向代理的区别?
  • 【语法】C++的string
  • Linux 权限系统和软件安装(二):深入理解 Linux 权限系统
  • Redis 高可用性:如何让你的缓存一直在线,稳定运行?
  • HTTP非流式请求 vs HTTP流式请求
  • Linux系统之DHCP网络协议
  • 深入探讨K8s资源管理和性能优化
  • Python 网络编程全攻略:核心知识与实战应用、高级应用场景、问题剖析、行业未来趋势等全解析
  • SpringBoot接入DeepSeek(硅基流动版)+ 前端页面调试
  • 【论文笔记-ECCV 2024】AnyControl:使用文本到图像生成的多功能控件创建您的艺术作品
  • 二十三种设计模式详解
  • 一周掌握Flutter开发--4、导航与路由
  • 清华大学DeepSeek赋能职场教程下载,清华大学DeepSeek文档下载(完成版下载)
  • 银河麒麟高级服务器操作系统通用rsync禁止匿名访问操作指南
  • RIP-AV:使用上下文感知网络进行视网膜动脉/静脉分割的联合代表性实例预训练
  • 【深度学习神经网络学习笔记(三)】向量化编程
  • python想学好你一定要掌握已下知识(新手)
  • RK3588开发板本地部署DeepSeek-R1
  • 向量数据库milvus部署