You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React点赞按钮无法保存用户点赞及权限控制失效问题排查

点赞按钮功能问题排查与修复

问题现状

  • 仅能保存当前用户浏览器本地的点赞状态,无法同步到服务器,其他用户看不到点赞变化
  • 未实现真实的登录用户权限控制,当前硬编码isAuthenticated = true,任何用户都能点击点赞

核心问题分析

  1. 本地存储导致状态孤立:使用localStorage保存状态,仅对当前浏览器有效,无法同步到数据库,其他用户自然获取不到点赞数据
  2. 权限控制完全失效:isAuthenticated被固定为true,没有真实校验用户登录状态(比如检查JWT令牌)
  3. 缺少服务器端点赞逻辑:没有后端接口处理点赞/取消点赞的请求,无法将状态持久化到数据库
  4. 点赞目标关联缺失:当前代码未明确点赞的对象(比如文章、评论ID),用户likes数组也没有存储具体的点赞标识

修复方案

前端代码修改(ToggleButton组件)

替换本地存储为服务器请求,校验真实登录状态,同步服务器端的点赞状态:

import React, { useState, useEffect } from "react";

// 接收点赞目标ID(比如文章ID)作为参数
const ToggleButton = ({ targetId }) => {
  const [isToggled, setIsToggled] = useState(false);
  const [isAuthenticated, setIsAuthenticated] = useState(false);

  // 初始化:检查登录状态+获取当前用户的点赞状态
  useEffect(() => {
    const token = localStorage.getItem("authToken");
    setIsAuthenticated(!!token);

    if (token) {
      fetch(`/api/likes/check/${targetId}`, {
        headers: { Authorization: `Bearer ${token}` }
      })
      .then(res => res.json())
      .then(data => setIsToggled(data.isLiked))
      .catch(err => console.error(err));
    }
  }, [targetId]);

  const handleToggle = () => {
    if (!isAuthenticated) {
      console.log("请先登录才能点赞");
      return;
    }

    const token = localStorage.getItem("authToken");
    const newState = !isToggled;

    // 调用后端接口更新点赞状态
    fetch(`/api/likes/toggle/${targetId}`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${token}`
      }
    })
    .then(res => res.json())
    .then(data => {
      if (data.success) setIsToggled(newState);
    })
    .catch(err => console.error(err));
  };

  const buttonStyle = {
    padding: "8px 16px",
    borderRadius: "4px",
    backgroundColor: isToggled ? "#4CAF50" : "#f44336",
    color: "#fff",
    border: "none",
    cursor: isAuthenticated ? "pointer" : "not-allowed",
    fontSize: "16px",
    opacity: isAuthenticated ? 1 : 0.7
  };

  return (
    <button onClick={handleToggle} style={buttonStyle}>
      {isToggled ? "取消点赞" : "点赞"}
    </button>
  );
};

export default ToggleButton;

后端代码修改

1. 新增点赞相关路由(在用户路由中添加)

// 检查用户是否已点赞某个目标
router.get("/likes/check/:targetId", auth, async (req, res) => {
  const { targetId } = req.params;
  const user = await User.findById(req.user._id);
  
  res.json({ isLiked: user.likes.includes(targetId) });
});

// 切换点赞状态(点赞/取消点赞)
router.post("/likes/toggle/:targetId", auth, async (req, res) => {
  const { targetId } = req.params;
  const user = await User.findById(req.user._id);
  
  if (user.likes.includes(targetId)) {
    // 取消点赞:移除目标ID
    user.likes = user.likes.filter(id => id !== targetId);
  } else {
    // 添加点赞:推入目标ID
    user.likes.push(targetId);
  }
  
  await user.save();
  res.json({ success: true });
});

2. 修复用户注册时的语法错误

原注册代码中likes > []是语法错误,改为手动初始化数组:

// 原错误代码
user = new User(
  _.pick(req.body, ["name", "email", "password", "biz", "likes" > []])
);

// 修改后
user = new User(
  _.pick(req.body, ["name", "email", "password", "biz"])
);
user.likes = []; // 手动初始化点赞数组

额外优化建议

  • 若需要统计总点赞数,建议单独创建Like模型,关联用户和点赞目标(如Article),便于高效查询总赞数和用户点赞记录
  • 前端可通过Context或Redux统一管理登录状态,避免每个组件重复读取localStorage

内容的提问来源于stack exchange,提问作者Omer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 03:08:11