Unsplash登录成功后背景色不更新,仅刷新页面生效的问题排查
问题解决:登录后图片背景色不自动更新与并发请求处理
核心问题分析
- 背景色不自动更新:
getUserProfile仅将用户名存入localStorage,但未更新Context中的username状态,导致ImageList中监听username的useEffect无法触发,进而不会调用getLikedPhotos获取点赞列表。此外,Login组件的useEffect逻辑存在异步时序问题,getToken执行完成前就判断token是否存在,导致getUserProfile可能无法正确触发。 - 并发请求无序:
getToken、getUserProfile、getLikedPhotos三个请求存在依赖关系,但当前代码未保证执行顺序,可能出现请求并发导致数据不一致的情况。
具体修改方案
1. 更新Context中的username状态
在appContext.js的getUserProfile方法中,添加dispatch更新Context的username:
const getUserProfile = async () => { try { const { data } = await axios.get(`https://api.unsplash.com/me`, { headers: { "Content-Type": "application/json", Authorization: "Bearer " + state.token, }, }); const { username } = data; localStorage.setItem("username", username); // 新增:更新Context中的username dispatch({ type: "SET_USERNAME", payload: { username }, }); } catch (error) { console.log(error); } };
同时在reducer.js中添加对应的处理逻辑:
import { SET_TOKEN, SET_LIKED_PHOTOS_ID, SET_USERNAME } from "./actions"; const reducer = (state, action) => { if (action.type === SET_TOKEN) { return { ...state, token: action.payload.access_token, }; } if (action.type === SET_LIKED_PHOTOS_ID) { return { ...state, likedPhotosId: action.payload.likedPhotosId, }; } // 新增:处理用户名更新 if (action.type === SET_USERNAME) { return { ...state, username: action.payload.username, }; } throw new Error(`no such action : ${action.type}`); };
在actions.js中添加SET_USERNAME常量:
export const SET_TOKEN = "SET_TOKEN"; export const SET_LIKED_PHOTOS_ID = "SET_LIKED_PHOTOS_ID"; export const SET_USERNAME = "SET_USERNAME";
2. 修复Login组件的异步时序问题
将Login中的useEffect改为串行处理异步请求,确保getToken完成后再执行getUserProfile:
import React, { useEffect } from "react" import { useAppContext } from "../context/appContext"; function Login() { const { handleClick, getToken, token, getUserProfile } = useAppContext(); useEffect(() => { const handleLoginFlow = async () => { if (window.location.search.includes("code=")) { await getToken(); // 等待token获取完成 } if (token) { await getUserProfile(); // 等待用户名获取完成 } }; handleLoginFlow(); }, [token, getToken, getUserProfile]); return ( <div> <button onClick={() => handleClick()}>Log in</button> </div> ); } export default Login;
3. 串行化依赖请求,避免并发问题
在getUserProfile完成后直接调用getLikedPhotos,确保依赖顺序:
const getUserProfile = async () => { try { const { data } = await axios.get(`https://api.unsplash.com/me`, { headers: { "Content-Type": "application/json", Authorization: "Bearer " + state.token, }, }); const { username } = data; localStorage.setItem("username", username); dispatch({ type: SET_USERNAME, payload: { username }, }); // 用户名获取后直接调用getLikedPhotos await getLikedPhotos(); } catch (error) { console.log(error); } };
4. 优化ImageList的渲染逻辑
将key属性绑定在最外层元素上,避免React渲染异常:
return ( <div className="result"> {images?.map((image) => ( <div key={image.id} // 将key移到最外层div style={{ backgroundColor: likedPhotosId?.includes(image.id) ? "red" : "", }} > <img src={image.urls.small} alt={image.alt_description} /> </div> ))} </div> );
效果验证
- 点击登录按钮跳转至Unsplash登录页,登录成功后重定向回本地页面。
- 页面会自动依次完成
token获取、用户名获取、点赞列表获取流程。 - 点赞过的图片背景色会自动变为红色,无需手动刷新页面。
- 所有依赖请求串行执行,不会出现并发导致的数据不一致问题。
内容的提问来源于stack exchange,提问作者john
相关产品推荐
相关产品推荐

