如何在点击订阅按钮后触发自定义hook useIsUserSubscribed重新渲染更新
这个需求完全可以实现,不需要推翻现有逻辑,下面是两种常用的实现方案:
方案1:改造自定义hook,暴露刷新方法(最推荐)
修改useIsUserSubscribed,将内部的订阅状态查询逻辑抽离并暴露给调用方,点击按钮调用完订阅接口后手动触发查询即可:
改造后的hook代码
import { useState, useEffect, useCallback } from "react"; import { useSelector } from "react-redux"; import { checkSubscription } from "../services"; function useIsUserSubscribed(publisherId) { const [userIsSubscribed, setUserIsSubscribed] = useState(null); const currentUserId = useSelector((state) => state.auth.user?.id); // 抽离查询逻辑,用useCallback包裹避免不必要的重生成 const fetchSubscriptionStatus = useCallback(async () => { if (!currentUserId || !publisherId) return; try { await checkSubscription(publisherId); setUserIsSubscribed(true); } catch (err) { setUserIsSubscribed(false); } }, [publisherId, currentUserId]); useEffect(() => { fetchSubscriptionStatus(); }, [fetchSubscriptionStatus]); // 同时返回状态和刷新方法 return [userIsSubscribed, fetchSubscriptionStatus]; } export default useIsUserSubscribed;
改造后的按钮组件代码
import React from "react"; // 注意原代码导入的add、remove和实际调用的addSubscription、removeSubscription不一致,属于笔误请自行修正 import { addSubscription, removeSubscription } from "../../services"; import useIsUserSubscribed from "../../hooks/useIsUserSubscribed"; const SubscribeUnsubscribeBtn = ({profilePageUserId}) => { // 解构获取状态和刷新方法 const [userIsSubscribed, refetchSubscriptionStatus] = useIsUserSubscribed(profilePageUserId); const onClick = async () => { if (userIsSubscribed) { await removeSubscription(profilePageUserId); } else { await addSubscription(profilePageUserId); } // 调用刷新方法重新拉取最新的订阅状态 await refetchSubscriptionStatus(); } // 可选:状态为null时展示加载态,避免请求过程中用户重复点击 if (userIsSubscribed === null) { return <button type="button" className="sub-edit-unsub-btn bsc-button" disabled>加载中</button> } return ( <button type="button" className="sub-edit-unsub-btn bsc-button" onClick={onClick}> {userIsSubscribed ? 'Subscribed' : 'Unsubscribed'} </button> ); }
方案2:乐观更新(体验更流畅)
如果不需要严格和后端实时对齐,可以直接在本地修改状态,减少一次额外的查询接口请求,用户点击后页面会立刻发生变化:
改造后的hook代码
import { useState, useEffect, useCallback } from "react"; import { useSelector } from "react-redux"; import { checkSubscription } from "../services"; function useIsUserSubscribed(publisherId) { const [userIsSubscribed, setUserIsSubscribed] = useState(null); const currentUserId = useSelector((state) => state.auth.user?.id); const fetchSubscriptionStatus = useCallback(async () => { if (!currentUserId || !publisherId) return; try { await checkSubscription(publisherId); setUserIsSubscribed(true); } catch (err) { setUserIsSubscribed(false); } }, [publisherId, currentUserId]); useEffect(() => { fetchSubscriptionStatus(); }, [fetchSubscriptionStatus]); // 额外返回状态更新方法,允许外部手动修改状态 return [userIsSubscribed, fetchSubscriptionStatus, setUserIsSubscribed]; }
改造后的点击逻辑
const onClick = async () => { // 先乐观更新状态,页面立刻响应 const newStatus = !userIsSubscribed; setUserIsSubscribed(newStatus); try { if (userIsSubscribed) { await removeSubscription(profilePageUserId); } else { await addSubscription(profilePageUserId); } } catch (err) { // 接口调用失败时回滚状态 setUserIsSubscribed(!newStatus); } }
不推荐的临时方案:如果不想修改hook,可以给按钮组件绑定一个数字类型的key,点击后将key+1触发组件重新挂载,但是会重走所有生命周期,性能较差,仅适合临时调试使用。
内容的提问来源于stack exchange,提问作者Simone Anthony
相关产品推荐
相关产品推荐

