为什么 ReactJS 没有将数组的更改反映到我的 UI?

问题描述 投票:0回答:1
import React, { useState } from "react";

export default function Recommend() {
  const [animeName, setAnimeName] = useState("");
  const [anilistURL, setanilistURL] = useState("");
  const [errorMsg, setErrorMsg] = useState("");
  const [loading, setLoading] = useState(false);
  const [loadingReviews, setLoadingReviews] = useState(false);
  const [reviewTitles, setreviewTitles] = useState([]);

  const handleSubmit = async () => {
    try {
      setLoading(true);
      setreviewTitles([]);
      setanilistURL("");
      setErrorMsg("");

      const response = await fetch("http://localhost:8000/get-anilist-url", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          anime_title: animeName,
        }),
      });
      if (!response.ok) {
        const errorData = await response.json();
        setErrorMsg(errorData.error || "Unable to get response");
      }
      const data = await response.json();
      setanilistURL(data.anilist_url || "No URL found");
      setErrorMsg("");
    } catch (error) {
      setErrorMsg("An error occurred: " + error.message);
    } finally {
      setLoading(false);
      getReviews();
    }
  };

  const getReviews = async () => {
    try {
      setLoadingReviews(true);
      setErrorMsg("");
      const anilistReviewsURL = anilistURL + "/reviews";
      const response = await fetch(
        "http://localhost:3000/api/v1/scrape/get-review-titles",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ reviewsLink: anilistReviewsURL }),
        }
      );
      const data = await response.json();
      if (!response.ok) {
        setErrorMsg(data.error || "Unable to get response");
      }
      setreviewTitles((prevTitles) => [
        ...prevTitles,
        data.reviewTitles
      ]);
      setErrorMsg("");

    } catch (error) {
      setErrorMsg("An error occurred: " + error);
    }
    finally {
      setLoadingReviews(false);
    }
  };

  return (
    <div className="flex flex-col h-screen bg-slate-700">
      <div className="flex-grow bg-slate-600 p-5 font-mono">
        {loading && <div className="text-white">Loading...</div>}
        {errorMsg && <div className="text-red-500">{errorMsg}</div>}
        {anilistURL && (
          <div className="text-yellow-100">
            <p>Anilist URL:</p>
            <a href={anilistURL} target="_blank" rel="noopener noreferrer">
              {anilistURL}
            </a>
          </div>
        )}
        {loadingReviews && <div className="text-white">Loading...</div>}
        {reviewTitles && (
          reviewTitles.map((reviewTitle) => {
            (
              <div className = "text-yellow-500 pt-3">
                {reviewTitle}
              </div>
            )
          })
        )}
      </div>
      <div className="p-4 flex items-center justify-between bg-slate-800">
        <h3 className="text-gray-500 text-3xl font-mono">
          Enter anime to be analyzed
        </h3>
        <textarea
          type="text"
          className="bg-slate-700 font-mono text-white text-2xl p-3 border-none outline-none w-full rounded-full"
          placeholder="Enter your prompt..."
          value={animeName}
          onChange={(e) => setAnimeName(e.target.value)}
        />
        <button
          className="bg-slate-700 font-mono text-white text-2xl p-4 rounded-full hover:bg-slate-600 transition duration-200 ml-5"
          onClick={handleSubmit}
        >
          Analyze
        </button>
      </div>
    </div>
  );
}

这是我的代码。我的问题主要是评论标题。即使我在 getReviews() 函数中设置它们的状态,它们也不会显示在 UI 上。我的 API 端点没有任何问题,我已经使用 Postman 对其进行了测试,并且 CORS 也得到了处理。在我在handleSubmit()函数中设置其状态后,Anilist URL正确显示,甚至出现正在加载...从loadingReviews状态,但我第一次单击分析按钮时,它显示anilist URL,但说无法获取状态404评论标题,第二次单击分析时,它会像以前一样显示 anist URL,从加载评论状态显示正在加载...,但不显示任何内容。根据我的研究,问题似乎出在 useState 的异步性质上,但我真的不明白如何解决这个问题。当我通过控制台记录 reviewTitles 时,它可以工作,尽管在第二次单击后(第一次我收到无法获取状态 404,如我之前所说),但前端没有像我预期的那样显示任何内容。我该如何解决这个问题?任何帮助将不胜感激。

我尝试使用回调函数设置 reviewTitles,但这也不起作用。控制台日志记录帮助我发现存在问题,但我不明白为什么第一次单击“分析”时没有显示任何内容,即使我在设置状态后直接进行控制台日志记录。我想过使用 useEffect() 但这似乎不是它的正确用例。

reactjs react-hooks
1个回答
0
投票

伙计们,我已经找到了我的问题的答案,我添加了一个 useEffect() 钩子,以便在 anistURL 发生更改时运行 getReviews() 函数,而不是直接从 handleSubmit 函数运行它,并使用 key prop 映射评论标题(感谢尼克·帕森斯)这似乎为我解决了问题。这是工作代码:

import React, { useState, useEffect } from "react";

export default function Recommend() {
  const [animeName, setAnimeName] = useState("");
  const [anilistURL, setAnilistURL] = useState("");
  const [errorMsg, setErrorMsg] = useState("");
  const [loading, setLoading] = useState(false);
  const [loadingReviews, setLoadingReviews] = useState(false);
  const [reviewTitles, setReviewTitles] = useState([]);

  useEffect(() => {
    if (anilistURL) {
      getReviews(anilistURL);
    }
  }, [anilistURL]);

  const handleSubmit = async () => {
    try {
      setLoading(true);
      setAnilistURL("");
      setReviewTitles([]);
      setErrorMsg("");

      const response = await fetch("http://localhost:8000/get-anilist-url", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          anime_title: animeName,
        }),
      });

      if (!response.ok) {
        const errorData = await response.json();
        setErrorMsg(errorData.error || "Unable to get response");
        setLoading(false);
        return;
      }

      const data = await response.json();
      setAnilistURL(data.anilist_url || "No URL found");
    } catch (error) {
      setErrorMsg("An error occurred: " + error.message);
      setLoading(false);
    }
  };

  const getReviews = async (url) => {
    try {
      setLoadingReviews(true);
      setErrorMsg("");
      const anilistReviewsURL = url + "/reviews";

      const response = await fetch(
        "http://localhost:3000/api/v1/scrape/get-review-titles",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ reviewsLink: anilistReviewsURL }),
        }
      );

      if (!response.ok) {
        const errorData = await response.json();
        setErrorMsg(errorData.error || "Unable to get response");
        setLoadingReviews(false);
        return;
      }

      const data = await response.json();
      setReviewTitles(data.reviewTitles || []);
    } catch (error) {
      setErrorMsg("An error occurred: " + error.message);
    } finally {
      setLoadingReviews(false);
    }
  };

  return (
    <div className="flex flex-col h-screen bg-slate-700">
      <div className="flex-grow bg-slate-600 p-5 font-mono">
        {loading && <div className="text-white">Loading...</div>}
        {errorMsg && <div className="text-red-500">{errorMsg}</div>}
        {anilistURL && (
          <div className="text-yellow-100">
            <p>Anilist URL:</p>
            <a href={anilistURL} target="_blank" rel="noopener noreferrer">
              {anilistURL}
            </a>
          </div>
        )}
        {loadingReviews && <div className="text-white">Loading reviews...</div>}
        {reviewTitles.length > 0 && (
          <div>
            <h3 className="text-white">Review Titles:</h3>
            {reviewTitles.map((reviewTitle, index) => (
              <div key={index} className="text-yellow-500 pt-3">
                {reviewTitle}
              </div>
            ))}
          </div>
        )}
      </div>
      <div className="p-4 flex items-center justify-between bg-slate-800">
        <h3 className="text-gray-500 text-3xl font-mono">
          Enter anime to be analyzed
        </h3>
        <textarea
          type="text"
          className="bg-slate-700 font-mono text-white text-2xl p-3 border-none outline-none w-full rounded-full"
          placeholder="Enter your prompt..."
          value={animeName}
          onChange={(e) => setAnimeName(e.target.value)}
        />
        <button
          className="bg-slate-700 font-mono text-white text-2xl p-4 rounded-full hover:bg-slate-600 transition duration-200 ml-5"
          onClick={handleSubmit}
        >
          Analyze
        </button>
      </div>
    </div>
  );
}
© www.soinside.com 2019 - 2024. All rights reserved.