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

登录后已点赞图片背景未实时更新,仅刷新生效的问题求助

问题描述
  • 用户登录后,已点赞的图片背景应自动变为红色,但当前仅在页面刷新后才触发颜色变化,登录成功后无实时效果。
  • 存在多请求并发的情况,需要妥善处理避免竞态条件。
解决方案

1. 实现登录后实时更新图片点赞状态

登录成功前,页面拉取的图片数据是未登录状态下的结果,不包含当前用户的点赞状态(liked_by_user字段)。需要在登录完成后重新请求数据,替换原有图片列表以获取带用户点赞标记的信息。

修改Home.js中的逻辑,监听username的变化(登录成功后username会被设置),触发重新拉取图片:

// Home.js
import { useAppContext } from "../context/appContext";
import { useState, useEffect } from "react";
import axios from "axios";

function Home() {
  const [page, setPage] = useState(1);
  const [query, setQuery] = useState("landscape");
  const [images, setImages] = useState([]);
  const [loading, setLoading] = useState(false);

  const { token, username, getUserProfile, getToken } = useAppContext();

  const clientId = process.env.REACT_APP_UNSPLASH_KEY;

  useEffect(() => {
    if (window.location.search.includes("code=") && !token) {
      getToken();
    }

    if (token) {
      getUserProfile();
    }
  }, [token]);

  // 新增:登录成功后重置并重新拉取图片
  useEffect(() => {
    if (username) {
      setPage(1);
      setImages([]);
      fetchImages();
    }
  }, [username]);

  const fetchImages = () => {
    setLoading(true);

    let params = {
      page: page,
      query: query || "landscape",
      per_page: 30,
    };

    let headers = {};

    if (username) {
      headers = {
        Authorization: `Bearer ${token}`,
      };
    } else {
      params = { ...params, client_id: clientId };
    }

    axios
      .get("https://api.unsplash.com/search/photos", { headers, params })
      .then((response) => {
        // 使用函数式更新避免闭包捕获旧state
        setImages(prev => [...prev, ...response.data.results]);
      })
      .catch((error) => {
        console.log(error);
      })
      .finally(() => {
        setLoading(false);
      });
    setPage(prev => prev + 1);
  };

  useEffect(() => {
    fetchImages();
    setQuery("");
  }, []);

  return (
    <div>
      <Login />
      {loading && <Loader />}
      <ImageList images={images} fetchImages={fetchImages} />
    </div>
  );
}

export default Home;

2. 处理多请求并发问题

使用AbortController取消未完成的请求,避免快速触发多次请求时,旧请求延迟返回覆盖新请求结果的竞态问题。

修改Home.js的fetchImages函数:

// Home.js
function Home() {
  // 用于存储AbortController实例
  const abortControllerRef = useRef(null);

  // ...其他state和context引用

  const fetchImages = () => {
    // 取消之前未完成的请求
    if (abortControllerRef.current) {
      abortControllerRef.current.abort();
    }
    abortControllerRef.current = new AbortController();

    setLoading(true);

    let params = {
      page: page,
      query: query || "landscape",
      per_page: 30,
    };

    let headers = {};

    if (username) {
      headers = {
        Authorization: `Bearer ${token}`,
      };
    } else {
      params = { ...params, client_id: clientId };
    }

    axios
      .get("https://api.unsplash.com/search/photos", { 
        headers, 
        params,
        signal: abortControllerRef.current.signal // 绑定取消信号
      })
      .then((response) => {
        setImages(prev => [...prev, ...response.data.results]);
      })
      .catch((error) => {
        // 忽略请求取消的错误
        if (error.name !== 'AbortError') {
          console.log(error);
        }
      })
      .finally(() => {
        setLoading(false);
      });
    setPage(prev => prev + 1);
  };

  // 组件卸载时取消未完成的请求
  useEffect(() => {
    return () => {
      if (abortControllerRef.current) {
        abortControllerRef.current.abort();
      }
    };
  }, []);

  // ...其他useEffect和返回内容
}

关键说明

  • 登录后通过监听username变化触发重新请求,此时请求携带用户token,Unsplash API会返回包含liked_by_user字段的图片数据,ImageList中的背景色会自动更新为红色。
  • AbortController确保只有最新的请求结果生效,避免旧请求延迟返回导致的状态混乱。
  • 使用函数式更新setState(prev => ...),避免闭包捕获旧state的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 17:15:36