Next.js卡片组件收藏按钮无法触发API调用问题求助
你的场景完全适配SWR,用SWR可以完美解决多页面同个商品收藏状态同步的问题,先排查现有代码的问题,再给出接入SWR后的完整实现:
现有代码问题排查
- 请求方法颠倒:新增收藏应该发POST,取消收藏发DELETE,你当前两个方法的
method配置完全写反了 - axios参数错误:axios请求配置中,请求体的字段名是
data不是body,你写的body字段不会被axios识别,请求不会携带商品ID参数 - session未获取:代码中直接使用
session.token但没有前置获取session的逻辑,如果用next-auth的话需要先调用useSession()钩子拿到登录态 - 状态更新逻辑不合理:点击后直接修改收藏状态,不管请求是否成功,一旦接口报错会出现前端显示和后端实际状态不一致的问题
- 多组件状态不同步:每个Card组件单独维护收藏状态,同一个商品在不同页面的Card组件状态无法同步,这正是SWR的适用场景。
接入SWR后的实现方案
SWR会基于请求key全局缓存数据,所有引用同一个key的组件都会自动同步状态,不需要自己额外做状态管理。
第一步:安装依赖
npm install swr next-auth (如果已经装了可以跳过)
第二步:修改后的完整Card组件代码
import React from "react" import Link from 'next/link' import useSWR, { mutate } from 'swr' import { useSession } from 'next-auth/react' import Styles from "./card.module.scss" import axios from 'axios' // 封装axios请求器给SWR用 const fetcher = (url, token) => axios.get(url, { headers: { Authorization: `Bearer ${token}` } }).then(res => res.data) export default function Card(props) { const { data: session } = useSession() // 全局缓存当前用户的收藏列表,所有Card组件共用这份数据 const { data: favorites = [] } = useSWR( session ? [`${process.env.NEXT_PUBLIC_BASE_API}/favorites`, session.user.token] : null, fetcher ) // 直接从全局收藏列表判断当前商品是否被收藏,不需要单独维护state const isFavorited = favorites.some(item => item.advert === props["@id"]) const toggleFavorite = async () => { if (!session) return // 未登录直接返回 try { if (isFavorited) { // 取消收藏发DELETE请求 await axios({ method: 'DELETE', url: `${process.env.NEXT_PUBLIC_BASE_API}/favorites`, headers: { Authorization: "Bearer " + session.user.token, }, data: { advert: props["@id"] } }); } else { // 新增收藏发POST请求 await axios({ method: 'POST', url: `${process.env.NEXT_PUBLIC_BASE_API}/favorites`, headers: { Authorization: "Bearer " + session.user.token, }, data: { advert: props["@id"] } }); } // 请求成功后更新SWR全局缓存,所有用到收藏列表的组件都会自动同步状态 mutate([`${process.env.NEXT_PUBLIC_BASE_API}/favorites`, session.user.token]) } catch (error) { if (error.response) { throw new Error(error.response.data.message) } } } return ( <div className={Styles.card}> <Link href={"/annonce?id="+props.id} passHref> <a className={Styles.imageCard} style={{backgroundImage: `url(${props.imageSrc})`}}> <p className={Styles.localisationCard}><span className="material-icons">location_on</span>{props.localisation}</p> </a> </Link> <div className={`${Styles.favCard} ${isFavorited ? Styles.active : ''}`} onClick={toggleFavorite}></div> <p className={Styles.titleCard}>{props.title}</p> <p className={Styles.pricesCard}><span className="material-icons-outlined">local_offer</span>Prix : {props.prices}</p> <p className={Styles.eligibilitesCard}><span className="material-icons-outlined">check_circle</span>Eligibilité ({props.eligibilities})</p> </div> ) }
改动说明
- 用SWR全局缓存当前用户的收藏列表,所有Card组件共享同一份数据,同一个商品在任何页面的收藏状态都会自动同步
- 修正了请求方法和axios参数的错误
- 登录态通过next-auth的useSession钩子获取,避免session未定义的问题
- 只有请求成功后才会更新缓存状态,避免前端和后端状态不一致
- 去掉了冗余的本地favoris状态,直接从全局收藏列表判断是否已收藏
内容的提问来源于stack exchange,提问作者Mélanie Croce
相关产品推荐
相关产品推荐

