简体   繁体   English

React state 更改不会导致重新渲染

[英]React state change does not result in a rerender

I'm using React Infinite Scroller to render a list of posts.我正在使用React Infinite Scroller来呈现帖子列表。

My load more results function is called 3 times and therefore the result is updated three times (can be seen with a console.log)我加载更多结果 function 被调用了 3 次,因此结果更新了 3 次(可以通过 console.log 看到)

I render the posts with:我用以下方式渲染帖子:

{results.map((result) => (
    <Widget data={result} key={result.id} />
))}

This updates the result the first two times, but when the state changes for the third time, it doesn't render any more results.这会更新前两次结果,但是当 state 第三次更改时,它不再呈现任何结果。

My full code:我的完整代码:

import React, { useState } from "react";
import InfiniteScroll from "react-infinite-scroller";
import LoadingIndicator from "./loading";
import { request } from "../communication";

const InfiniteResults = ({ endpoint, widget }) => {
  let [results, setResults] = useState([]);
  let [hasMoreResults, setHasMoreResults] = useState(true);

  const Widget = widget;

  function loadMoreResults(page) {
    // prevent from making more requests while waiting for the other one to complete
    setHasMoreResults(false);

    request
      .get(endpoint, {
        offset: page * 10,
      })
      .then(function gotResults(response) {
        const data = response.data;

        const resultsCopy = results;
        data.results.forEach(function saveResultToState(result) {
          resultsCopy.push(result);
        });
        setResults(resultsCopy);
        console.log(resultsCopy);
        console.log(results);

        if (!data.next) {
          setHasMoreResults(false);
        } else {
          setHasMoreResults(true);
        }
      });
  }

  return (
    <InfiniteScroll
      pageStart={-1}
      loadMore={loadMoreResults}
      hasMore={hasMoreResults}
      loader={<p key={0}>Loading...</p>}
    >
      {results.map((result) => {
        console.log("rerender");
        return <Widget data={result} key={result.id} />;
      })}
    </InfiniteScroll>
  );
};

export default InfiniteResults;

Your problem is with your state update:您的问题在于您的 state 更新:

const resultsCopy = results;
data.results.forEach(function saveResultToState(result) {
  resultsCopy.push(result);
);
setResults(resultsCopy);

When you do const resultsCopy = results;当你做const resultsCopy = results; , you're not actually copying the array; ,您实际上并没有复制数组; you're just referring to the same array by another name.您只是用另一个名称引用同一个数组。 That means that when you start adding elements to it, you are adding them directly to the one controlled by React's useState hook.这意味着当您开始向其中添加元素时,您将它们直接添加到由 React 的useState钩子控制的元素中。 All state updates should be done through the setState ( setResults in your case) function that useState returns.所有 state 更新都应通过useState返回的setState (在您的情况下为setResults ) function 完成。

To perform an update on the previous state, the best way to do that is to call the setResults function with a function as an argument, that takes the previous state as its own argument. To perform an update on the previous state, the best way to do that is to call the setResults function with a function as an argument, that takes the previous state as its own argument. This ensures that the state updates are sequential (each update happens after the previous one was completed).这确保了 state 更新是连续的(每次更新都发生在前一次更新完成之后)。

setResults(prevState => prevState.concat(data.results));
// or
setResults(function (prevState) {
  return prevState.concat(data.results);
});

Here I have also made use of the concat function that combines two arrays into one and returns the result.这里我还使用了concat function 将两个 arrays 合二为一并返回结果。 That way you are not updating the previous state with the push calls.这样,您就不会使用push调用更新以前的 state。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM