javascript - 反应加载消息
问题描述
我正在开发一个反应应用程序,该应用程序在单击按钮后会缩短 URL。我很难找出这样做的最佳逻辑。当我单击按钮时,加载消息不会显示。加载按钮出现,然后在消息加载时消失。
以下代码的当前行为如下。
- 当它呈现“正在加载...”时不显示。
- 我单击“缩短”按钮并显示“正在加载...”。
- 缩短的网址出现在“正在加载...”按钮下方。
缩短.js
import { useEffect, useState } from "react";
const Shorten = () => {
const [shortLink, setShortLink] = useState(null);
const [isPending, setIsPending] = useState(false);
const [input, setInput] = useState('example.org/very/long/link.html');
const url = "https://api.shrtco.de/v2/shorten?url=";
const fullUrl = (url.concat(input));
console.log(fullUrl);
useEffect(() => {
fetch(fullUrl)
.then(res => {
return res.json();
})
.then(data => {
setShortLink(data.result.short_link);
// setIsPending(false);
})
}, [fullUrl ])
// input
// value={input}
const loadMsg = () =>{
setIsPending(true);
}
return (
<main>
<section className="purple-card">
<input onInput={e => setInput(e.target.value)} type="text" placeholder="Shorten a link here..." className="shorten-input"/>
<button className="shorten-it" onClick={() => loadMsg()}>Shorten It!</button>
</section>
<section className="white-card">
{isPending && <div className="loading-text">Loading...</div>}
{shortLink && <div className="shorten-text">{shortLink}</div>}
<hr></hr>
<button className="shorten-it" >Copy</button>
</section>
</main>
);
}
export default Shorten;
解决方案
这里似乎有几个问题。加载消息和缩短的 URL 同时显示的原因是它们的渲染条件不是互斥的。修复这个问题就像在加载组件时不显示缩短的 URL 一样简单。
还有一些可能引起问题的是“缩短它!” 按钮不控制实际执行缩短操作,它只是将加载(待处理)状态设置为true
. 只要输入的值发生变化,就会运行缩短操作。基本上加载状态和缩短动作是相互独立的。
要解决此问题,您应该只在用户单击按钮时运行缩短操作,并同时将isPending
状态设置true
为(然后在完成时设置回false
)。
而不是useEffect
,您可以只使用单击按钮时调用的函数。
例如:
import { useState, useCallback } from "react";
const Shorten = () => {
const [shortLink, setShortLink] = useState(null);
const [isPending, setIsPending] = useState(false);
const [input, setInput] = useState('example.org/very/long/link.html');
const shortenUrl = useCallback(() => {
setIsPending(true);
const baseUrl = "https://api.shrtco.de/v2/shorten?url=";
const fullUrl = baseUrl + input;
fetch(fullUrl)
.then(res => res.json())
.then(data => {
setShortLink(data.result.short_link)
})
.finally(() => setIsPending(false));
}, [input]);
return (
<main>
<section className="purple-card">
<input onInput={e => setInput(e.target.value)} type="text" placeholder="Shorten a link here..." className="shorten-input"/>
<button className="shorten-it" onClick={shortenUrl}>Shorten It!</button>
</section>
<section className="white-card">
{isPending && <div className="loading-text">Loading...</div>}
{!isPending && shortLink && <div className="shorten-text">{shortLink}</div>}
<hr></hr>
<button className="shorten-it" >Copy</button>
</section>
</main>
);
}
export default Shorten;
或者,为了使加载/结果更加清晰互斥,您可以定义一个变量,其值为加载消息、结果 URL 或任何内容。例如:
const result = useMemo(() => {
if (isPending) {
return <div className="loading-text">Loading...</div>;
}
if (shortLink) {
return <div className="shorten-text">{shortLink}</div>;
}
return null;
}, [isPending, shortLink]);
然后像这样渲染:
<section className="white-card">
{result}
</section>