如何使用React hooks逐渐更新状态

huangapple go评论53阅读模式
英文:

How to update state incrementally with React hooks

问题

我正在进行一个React项目,我想要显示成千上万篇文章。我可以每次调用100篇,并希望在获取它们时显示出来。我该如何做?

我目前的尝试是触发useEffect,调用API,然后使用setState。但每当我这样做时,它会重新渲染组件,导致无限循环。

英文:

I am working on a React project where I would like to display thousands of articles. I can call them 100 at a time and want to display them as I bring them in. How do I do that?

My current attempt is to fire off useEffect and call the api and then use setState. But whenever I do that it re-renders the component and we get the infinite death loop going.

 const [articles, setArticles] = useState([]);

 useEffect(() => {
    const getArticles = async () => {
      let nextArticleNum = 0;
      let getMoreArticles = true;

      while (getMoreArticles) {
        const articlesRes = await axios.post("link-to-articles", { nextArticleNum: nextArticleNum });
        setArticles([...articles, ...articlesRes.data.articles])
        if (articles.length === 0) {
          getMoreArticles = false;
        } else {
          nextArticleNum = nextArticleNum + 100;
        }
      }
    }

    getArticles();
  }, [])

答案1

得分: 0

我尝试了你的代码,但看不到任何问题。

但在这种情况下,我建议你将 nextArticleNum 放入 useState 中,并在获取API后将 setNewArticleNum 设置为 nextArticleNum 直到文章结果长度为 0。

然后,我们每次 newArticleNum 改变时调用API。

const [articles, setArticles] = useState([]);
const [nextArticleNum, setNextArticleNum] = useState(0);

useEffect(() => {
  const getArticles = async () => {
    const articlesRes = await axios.post("link-to-articles", { nextArticleNum: nextArticleNum });
    if (articlesRes.length <= 0) return;
    setArticles([...articles, ...articlesRes.data.articles]);
    setNextArticleNum(nextArticleNum + 20);
  };

  getArticles();
}, [nextArticleNum]);
英文:

I tried your code but cant see any probs.

But in this case i suggest you move nextArticleNum into an useState and setNewArticleNum after get api till articles result length = 0.

Then, we call the api everytime newArticleNum change.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const [articles, setArticles] = useState([]);
  const [nextArticleNum , setNextArticleNum ] = useState(0)

  useEffect(() =&gt; {
    const getArticles = async () =&gt; {
      const articlesRes = await axios.post(&quot;link-to-articles&quot;, { nextArticleNum: nextArticleNum })
      if(articlesRes.length &lt;= 0) return;
      setArticles([...articles, ...articlesRes.data.articles])
      setNextArticleNum(nextArticleNum  + 20);
    };

    getArticles();
  }, [nextArticleNum]);

<!-- end snippet -->

答案2

得分: 0

我还没有运行我写的代码但我认为可以这样写

const [articles, setArticles] = useState([]);

const getArticles = async (nextArticleNum) => {
    const articlesRes = await axios.post("链接到文章", { nextArticleNum: nextArticleNum });
    setArticles((value) => {
      const data = articlesRes.data.articles ?? [];
      return [...value, ...data];
    });
}

useEffect(() => {
    getArticles(0);
}, []);


useEffect(() => {
  const nextArticleNum = Math.floor(articles / 100);
  if(nextArticleNum < 10) {
    getArticles(nextArticleNum);
  }
}, [articles])
英文:

I haven't run the code I wrote, but I think I can write it this way.


const [articles, setArticles] = useState([]);

const getArticles = async (nextArticleNum) =&gt; {
    const articlesRes = await axios.post(&quot;link-to-articles&quot;, { nextArticleNum: nextArticleNum });
    setArticles((value) =&gt; {
      const data = articlesRes.data.articles ?? [];
      return [...value, ...data];
    });
}

useEffect(() =&gt; {
    getArticles(0);
}, []);


useEffect(() =&gt; {
  const nextArticleNum = Math.floor(articles / 100);
  if(nextArticleNum &lt; 10) {
    getArticles(nextArticleNum);
  }
}, [articles])

答案3

得分: 0

Sure, here's the translation of the provided text:

首先 - 我认为你的无限死循环是由这行代码引起的:

if (articles.length === 0)

它可能应该改为:

if (articlesRes.data.articles.length === 0)

因为这会在没有返回结果时(超出边界)停止循环。

其次 - 除了减少axios结果集的大小之外,通过将其分成100个记录块,你并没有真正获得什么好处,因为不断的状态更新将导致组件反复刷新,直到检索完所有记录,可能会中断用户在UI中的交互。

我建议使用类似虚拟/无限滚动的方法。这种方法的要点是,在获取初始数据页之后,只有在需要时才获取更多的记录,即当其滚动到视图中时。

这里有一篇文章描述了这种方法,并包括一个示例,你可以根据自己的需求进行修改。还有一些库提供了这种功能。

英文:

Firstly - I think your infinite death loop is caused by this line:

if (articles.length === 0)

it probably should have been

if (articlesRes.data.articles.length === 0)

as this would stop the loop if no results were returned (bounds exceeded)

Secondly - other than reducing the size of the axios resultset you are not really gaining anything by breaking this into 100 rec chucks as the constant state updates will cause the component to repeatably refresh until all records are retrieved - likely interrupting user interaction within the UI.

I would suggest using an approach like virtual/infinite scrolling. The gist of this approach is, after you get the initial page of data you only get further records when you need it i.e. as it would scroll into view.

Here's an article which describes the approach and includes an example which you could alter to fit your needs. There are also a number of libraries which provide this functionality.

huangapple
  • 本文由 发表于 2023年6月13日 08:32:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76461040.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定