从零开始用react + tailwindcss + express + mongodb实现一个聊天程序(八) 聊天框用户列表
简单画了个聊天框 就是咱们的HomePage.jsx
1.后端接口开发
在server/src/index.js 新增 messagesRoutes
先引入
import messageRoutes from './routes/message.route.js'
// 消息接口
app.use('/api/messages', messageRoutes)
在routes文件夹下新建message.route.js 有3个路由 左侧用户列表 点击用户获取消息列表 发送消息接口
在controllers下面 新建message.controller.js 先实现获取前端左侧边栏用户列表接口
import User from '../models/user.model.js';
export const getUsersForSidebar = async (req, res) => {
try {
// 获取当前登录用户的id
const loggedInUserId = req.user._id;
// 过滤用户 所有不等于当前用户id 的用户 .select 查询时排除password
const filteredUsers = await User.find({ _id: { $ne: loggedInUserId } }).select("-password");
res.status(200).json(filteredUsers);
} catch (error) {
console.log("error in getSidebarUsers: ");
res.status(500).json({ message: error.message });
}
}
// 点击左侧用户时,获取该用户与当前用户之间的聊天记录
export const getMessages = async (req, res) => {
}
// 发送消息
export const sendMessage = async (req, res) => {
}
2.测试接口
使用postman测试接口成功
3.前端页面
修改HomePage.jsx页面
在components下面 新建3个组件 Sidebar NoChatSelected ChatBox
新建useChatStore.js
import {create} from "zustand";
import toast from "react-hot-toast"
import axiosInstance from "../lib/axios";
export const useChatStore = create((set, get) => ({
users: [],
selectedUser: null,
isUserLoading:false,
getUsers: async () => {
set({isUserLoading: true});
try {
const res = await axiosInstance.get("/messages/users");
set({users: res.data});
} catch{
toast.error("Error while fetching users");
} finally{
set({isUserLoading: false});
}
},
// 选择一个联系人
setSelectedUser: (user) => {
set({selectedUser: user});
}
}))
然后我们完善Sidebar.jsx
import { useEffect} from "react"
import { useChatStore } from "../store/useChatStore"
import {User} from "lucide-react"
const Sidebar = () => {
const {getUsers,users,selectedUser, setSelectedUser,isUsersLoading} = useChatStore()
useEffect(() => {
getUsers()
},[getUsers])
if(isUsersLoading) return <div>Loading...</div>
return (
<aside className="h-full w-20 lg:w-72 border-r border-base-300 flex flex-col transition-all duration-200">
<div className="border-b border-base-300 w-full p-5">
<div className="flex items-center gap-2">
<User className="size-6" />
<span className="font-medium hidden lg:block">联系人</span>
</div>
{/* 在线人员过滤 */}
</div>
<div className="overflow-y-auto w-full py-3">
{users.map((user) =>(
<button
key={user._id}
onClick={() => setSelectedUser(user)}
className={`w-full p-3 flex items-center gap-3
hover:bg-base-300 transition-colors
${selectedUser?._id===user._id ? "bg-base-300 ring-l ring-base-300":""}
`}
>
<div className="relative mx-auto lg:mx-0">
<img
src={user.profilePic || "https://picsum.photos/200" }
alt={user.userName}
className="size-12 object-cover rounded-full"
/>
</div>
{/* 用户信息 只在大屏显示 */}
<div className="hidden lg:block text-left min-w-0">
<div className="font-medium truncate">{user.userName}</div>
</div>
</button>
))}
</div>
</aside>
)
}
export default Sidebar
效果如下
好这篇就到这 下一篇 实现聊天功能