React ProfileCard星标收藏功能实现与点击事件冲突处理
React个人资料卡片星标收藏功能修改方案
核心修改点
- 移除原评分功能相关冗余代码,仅保留星标作为收藏按钮
- 阻止星标点击事件冒泡,避免触发卡片跳转详情的逻辑
- 基于登录状态条件渲染星标,未登录用户完全不展示该组件
完整修改后代码
import React, {useState, useEffect} from 'react'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faMapMarkerAlt} from '@fortawesome/free-solid-svg-icons'; import {ServiceType} from 'shared/models/profile/serviceType'; import {toTitleCase} from 'shared/utils/string'; import {FeeKind} from 'shared/models/fee-kind/FeeKind'; import {useAuth} from 'shared/hooks/useAuth'; import {ProfileCardFee} from 'shared/components/ProfileCard/ProfileCardFee/ProfileCardFee'; import {StarRatingStar} from 'shared/components/StarRating/StarRatingStar'; // 请替换为你实际的收藏接口引入路径 import { createFavoriteAsync } from 'src/api/favorite'; import './style.scss'; import {getFullName} from 'shared/utils/profile'; import {IProfile} from 'shared/models/profile/IProfile'; interface IProfileCardProps { profile: IProfile; onClickDetail?: () => void; } export const ProfileCardDetails = ({profile, onClickDetail}: IProfileCardProps) => { const fullName = getFullName(profile); const professionTitle = profile.profession ? toTitleCase(profile.profession) : null; // 替换原评分状态为收藏状态 const [isFavorited, setIsFavorited] = useState<boolean>(false); const {isAuthenticated, tokenData} = useAuth(); // 收藏点击逻辑 const handleFavoriteClick = async (e: React.MouseEvent) => { // 阻止事件冒泡,不触发外层卡片的跳转逻辑 e.stopPropagation(); if (!tokenData) return; try { await createFavoriteAsync({ user_id: tokenData.id, profile_id: profile.id, }); // 切换收藏状态,也可根据接口返回值更新 setIsFavorited(prev => !prev); } catch (err) { // 可按需添加收藏失败的提示逻辑 console.error('收藏失败', err); } }; return ( <div onClick={onClickDetail} className="ProfileCard__details d-flex justify-content-between"> <div> <div className="ProfileCard__profession">{professionTitle || 'undefined'}</div> <div className="ProfileCard__title">{fullName}</div> <div className="ProfileCard__location"> <FontAwesomeIcon icon={faMapMarkerAlt} className="ProfileCard__location-icon" /> {profile?.contact_details_display?.city} </div> </div> <div className="flex_colum_end"> {/* 仅登录用户展示收藏星标 */} {isAuthenticated ? ( <div className="text_align_end ProfileCard__star_icon"> <StarRatingStar isClickable={true} onClick={handleFavoriteClick} isActive={isFavorited} // 移除原评分需要的hover相关逻辑,不需要可直接删除对应属性 onMouseEnter={() => {}} onMouseLeave={() => {}} isHover={false} /> </div> ) : null} <div className={ profile && profile.service_types && profile.service_types.includes('FIXED_FEES' as ServiceType) ? 'flex_row_center mobileDayHour Hourly_rate_responsive' : 'flex_center' } > <div className={ profile && profile.service_types && profile.service_types.includes('FIXED_FEES' as ServiceType) ? 'text_align_end' : 'text_align_end' } > <ProfileCardFee amount={profile.service_details?.hour_rate as number} kind={FeeKind.Hour} /> </div> <div className="text_align_end pl-3"> <ProfileCardFee amount={profile.service_details?.day_rate as number} kind={FeeKind.Day} /> </div> </div> <div className="fixed_fee_enum_div"> {profile && profile.service_types && profile.service_types.includes('FIXED_FEES' as ServiceType) && ( <> <div className="fixed_fee_enum_svg"> <img className="fixed_fee_enum_svg_icon" src="/assets/profileIcons/lock.svg" alt="Rightful Logo" /> </div> <div className="fixed_fee_enum_text">Fixed Fee Options</div> </> )} </div> </div> </div> ); };
补充说明
如果需要初始化星标的选中状态,可以在组件挂载时调用查询接口,判断当前用户是否已经收藏该资料,更新isFavorited的初始值即可。如果需要支持取消收藏功能,也可以在handleFavoriteClick里判断当前状态,调用对应的取消收藏接口即可。
内容的提问来源于stack exchange,提问作者Chris Dobbs
相关产品推荐
相关产品推荐

