首页 > 解决方案 > 反应加载消息

问题描述

我正在开发一个反应应用程序,该应用程序在单击按钮后会缩短 URL。我很难找出这样做的最佳逻辑。当我单击按钮时,加载消息不会显示。加载按钮出现,然后在消息加载时消失。

以下代码的当前行为如下。

  1. 当它呈现“正在加载...”时不显示。
  2. 我单击“缩短”按钮并显示“正在加载...”。
  3. 缩短的网址出现在“正在加载...”按钮下方。

缩短.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;

标签: javascriptreactjsuse-effect

解决方案


这里似乎有几个问题。加载消息和缩短的 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>

推荐阅读