如何避免React自定义hook在组件首次渲染时发起请求?
解决方案:手动触发请求,避免首次渲染自动调用
你的问题核心在于当前的useFetchLink会在linkToShorten变化时自动发起请求,包括首次渲染时nextLink初始值(undefined)触发的请求。要避免这种情况,最直接的方法是把hook改成手动触发模式,让组件完全控制请求时机。
修改自定义hook:返回触发函数
调整useFetchLink,去掉自动执行的useEffect,而是把请求函数返回给组件,由组件决定什么时候调用:
const useFetchLink = () => { const [shortLink, setShortLink] = useState(""); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const fetchLink = async (linkToShorten) => { if (!linkToShorten) return; // 空值不发起请求 setLoading(true); try { const response = await fetch( `https://api.shrtco.de/v2/shorten?url=${linkToShorten}` ); if (response.ok) { const data = await response.json(); setShortLink(data.result.short_link); setError(""); // 成功时清空错误 } else { throw response.status; } } catch (err) { setError(err); setShortLink(""); // 失败时清空短链接 } finally { setLoading(false); } }; return { shortLink, loading, error, fetchLink }; };
修改组件:在点击时触发请求
调整LinkShortener组件,在点击按钮时调用hook返回的fetchLink,并在请求完成后更新链接数组:
export default function LinkShortener({ setLinkArr }) { const inputRef = useRef(null); const { shortLink, loading, error, fetchLink } = useFetchLink(); const handleClick = async () => { const inputValue = inputRef.current.value.trim(); if (!inputValue) return; // 空输入不处理 await fetchLink(inputValue); // 请求成功后更新链接数组 if (shortLink) { setLinkArr((prev) => [ ...prev, { id: prev.length === 0 ? 1 : prev[prev.length - 1].id + 1, long: inputValue, short: shortLink, }, ]); inputRef.current.value = ""; } }; return ( <LinkShortenerContainer> <InputContainer> <LinkInput ref={inputRef} type="text" /> </InputContainer> <Button size={buttonSize.medium} text={ loading ? ( <Loader /> ) : ( <FormattedMessage id="linkShortener.shortenItBtn" defaultMessage="Shorten It !" /> ) } onClick={handleClick} ></Button> </LinkShortenerContainer> ); }
为什么这个方法有效?
- 去掉了hook中自动触发的
useEffect,请求完全由组件的点击事件控制,首次渲染时不会发起任何请求。 - 把
linkToShorten作为参数传给fetchLink,而不是依赖hook的入参触发,避免了初始值导致的误触发。 - 保留了hook内部的状态管理(loading、shortLink、error),组件依然可以获取请求状态。
额外优化点
- 在
fetchLink里增加空值判断,避免无效请求。 - 请求成功/失败时分别清空错误/短链接状态,避免状态残留。
内容的提问来源于stack exchange,提问作者user19786344
相关产品推荐
相关产品推荐

