React 获取更多数据并附加到状态

Mar*_*nho 1 javascript typescript reactjs react-hooks

当加载更多数据并附加到状态时,我遇到了经典的无限滚动问题。

我有一个页面,其中显示了自定义的无限滚动城市列表。
这些城市是从外部库中获取的。

import { City, Country, CitiesQuery } from "an-external-library";

export const CountryComponent: FC<Props> = ({ country: Country }) => {
  const [cities, setCities] = useState<City[]>([]);
  const [citiesQuery, setCitiesQuery] = useState<CitiesQuery>();

  const loadMoreCities = useCallback(() => {
    console.log("loadMoreCities", "cities", cities);

    citiesQuery
      ?.load((newCities) => {
        console.log("loadMoreCities", "newCities", newCities);
        const updatedCities = [...cities, ...newCities];
        console.log("loadMoreCities", "updatedCities", updatedCities);
        setCities(updatedCities);
      })
      .then(() => setCitiesQuery(citiesQuery))
      .catch(console.error)
  }, [cities]); // I've tried adding more dependencies here

  useEffect(() => {
    const query = country.createCitiesQuery()
    query.limit = 3; // example
    query
      .load(setCities)
      .then(() => setCitiesQuery(query)) // so that I can load more from where I left
      .catch(console.error)
  }, []);

  useEffect(() => {
    // so that we know what's actually being set
    console.log("cities", cities);
  }, [cities])

  return (
    <>
      // ...
      <CitiesList cities={cities} onScrollBottom={loadMoreCities}/>
    </>
  )
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,该loadMoreCities函数在更改时似乎没有更新cities,因此 insideloadMoreCities始终cities相同,并且不反映以前的附加。

这是一个运行日志的示例:

// initial render
cities: Array(0) []

// after first useEffect runs
cities: Array(3) ["A", "B", "C"]

// scroll bottom
loadMoreCities, cities: Array(3) ["A", "B", "C"]
loadMoreCities, newCities: Array(3) ["D", "E", "F"]
loadMoreCities, updatedCities: Array(6) ["A", "B", "C", "D", "E", "F"]
cities: Array(6) ["A", "B", "C", "D", "E", "F"]

// scroll bottom again
loadMoreCities, cities: Array(3) ["A", "B", "C"]  // <---- this is a problem
loadMoreCities, newCities: Array(3) ["G", "H", "I"]
loadMoreCities, updatedCities: Array(6) ["A", "B", "C", "G", "H", "I"]
cities: Array(6) ["A", "B", "C", "G", "H", "I"] // <---- as consequence, we lost ["D", "E", "F"]
Run Code Online (Sandbox Code Playgroud)

我尝试在 中添加所有可能的依赖项组合useCallback,但似乎没有任何效果。
我确信我错过了一些非常简单的东西,但看不出是什么。

Kon*_*owy 6

解决方案

尝试:

.load((newCities) => {
  setCities(cities => [...cities, ...newCities]);
})
Run Code Online (Sandbox Code Playgroud)

代替:

.load((newCities) => {
  setCities([...cities, ...newCities]);
})
Run Code Online (Sandbox Code Playgroud)

解释

setState可以接受一个值或一个 setter 函数

连续调用一个值将仅导致最后应用的

const [state, setState] = useState([])

setState([...state, 'a']) // current state = []
setState([...state, 'a']) // current state = []
setState([...state, 'c']) // current state = []
// the result will be `['c']`
Run Code Online (Sandbox Code Playgroud)

使用 setter 回调将使 React 记住每个回调,然后使用更新的数据运行每个回调

const [state, setState] = useState([])

setState(state => [...state, 'a']) // current state = []
setState(state => [...state, 'a']) // current state = ['a']
setState(state => [...state, 'c']) // current state = ['a', 'b']
// the result will be `['a', 'b', 'c']`
Run Code Online (Sandbox Code Playgroud)