我用 React 错了吗?

Am I using React wrong?

反应:我做错了吗?

所以我使用 React 已经有一段时间了,我已经能够利用 React 提供的功能创建一些非常酷的项目;挂钩,道具等。东西是。当我尝试在局部函数和全局函数之间传递变量和状态时,我的工作流程总是会停止,最终会出现意大利面条式代码的糟糕情况。 9/10 我最终陷入困境并违反了 React Hooks 规则,并使用非常普通的 JS 做事方式破解了它。然后我对自己说:“真是太棒了……不,我的意思是:当我尝试做一些比在页面上渲染组件更高级的事情时,如果我最终编写了 vanilla JS,为什么还要使用 React?”。是不是我的做法全错了?

这是一个例子:我有一个网页,它获取到一个用 Express 编写的 API,然后 returns 来自 MongoDB 数据库的数据。我使用自定义挂钩通过异步函数获取数据,然后在页面上显示所有内容。我有一个可以呈现所有内容的功能组件。我还使用 API 提取发送了一些查询数据,在此示例中,它是数字的字符串表示形式,它反过来设置了从数据库中收集的元素数量的限制。在 useEffect 挂钩上——它位于我之前提到的自定义挂钩内——我有要显示为依赖项的元素数量,因此每次该值更改时我都会获取 API。该值又由 1-1000 之间的滑块选择。每次我获取时,组件都会再次呈现并且所有内容都会闪烁。这是因为来自数据库的数据,以及我的 h1、滑块和 p-tags,都在同一个组件中。我想避免这种情况,所以我最初的想法是从数据库中提取除数据之外的所有内容到不同的组件并单独呈现。这就是问题所在。设置状态的滑块值,自定义挂钩又将其作为查询参数发送给 API,它们彼此之间不再有任何连接。我是不是用错了 React?这是使用上下文 API 的明智之处吗? 我基本上想在不同的功能组件之间共享状态,并在网页上单独呈现它们。

这是我的前端代码:

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

function useLoading(loadingFunction, sliderValue) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState();
  const [data, setData] = useState([]);

  async function load() {
    try {
      setLoading(true);
      setData(await loadingFunction());
    } catch (e) {
      setError(e);
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    load();
  }, [sliderValue]);

  return { loading, error, data };
}

async function fetchJSON(url, sliderValue) {
  const res = await fetch(url + `?numberOfMovies=${sliderValue}`);
  if (!res.ok) {
    throw new Error(`${res.status}: ${res.statusText}`);
  }
  return await res.json();
}

function randomNumber() {
  return Math.floor(Math.random() * 20000000000);
}

function LoadingPage() {
  return (
    <>
      <div className="loading one" />
      <div className="loading two" />
      <div className="loading three" />
      <div className="loading four" />
    </>
  );
}

function MovieCard({ movie: { title, plot, year, poster } }) {
  return (
    <div className={"movie-card"}>
      <h3>
        {title} ({year})
      </h3>
      <p>{plot}</p>
      {poster && <img width={100} src={poster} alt="Poster" />}
    </div>
  );
}

function ListMovies() {
  const [sliderValue, setSliderValue] = useState("300");
  const { loading, error, data } = useLoading(
    async () => fetchJSON("/api/movies", sliderValue),
    sliderValue
  );

  if (loading) {
    return <LoadingPage />;
  }
  if (error) {
    return (
      <div>
        <h1>Error</h1>
        <div>{error.toString()}</div>
      </div>
    );
  }

  function handleSliderChange(e) {
    let value = (document.getElementById("slider").value = e.target.value);
    document.getElementById("slider-value").innerHTML =
      value <= 1 ? `${value} movie` : `${value} movies`;
    setSliderValue(value);
  }

  return (
    <div className={"movies-container"}>
      <h1>Movies</h1>
      <p>Sorted by highest rated on Metacritic. All movies are from Ukraine.</p>
      <input
        onChange={handleSliderChange}
        type="range"
        min="1"
        max="1000"
        className="slider"
        id="slider"
      />
      <p id="slider-value" />
      <div>
        {data.map((movie) => (
          <MovieCard key={randomNumber()} movie={movie} />
        ))}
      </div>
    </div>
  );
}

export function MainPage() {
  return (
    <div>
      <ListMovies />
    </div>
  );
}

将国家“提升”到一个共同的祖先可能就足够了。 React 中的状态管理是一个非常复杂的主题,值得阅读标准方法。提升状态就是其中之一,因为组件“通常”不会“水平”地相互交谈。道具流下来。还有其他方法可以管理它,例如 Context 或 Redux,甚至是“非”React 方法,例如 pub/sub.

好消息是,在亲身经历了痛点之后,您会理解一些解决问题的模式。

在我看来,只要可行,我不确定做事的方式是否“错误”。但肯定有让生活变得艰难的方法,也有让生活更轻松的方法。

如果您可以将您的问题缩减为一个非常具体的问题,而无需太多解释,您可能会得到更好的帮助。