useState 数组和异步作用域查找

useState array and async scope lookup

考虑依赖于两个异步调用的组件的状态。一个是初始呼叫,另一个是重复呼叫。 两者都更改由 useState 控制的数组。通过将旧数组展开为文字来附加数组。

问题是当两个调用解析时它们设置了相同的状态,但旧数组的传播是从调用 useEffect 时开始的范围查找。所以其中一个电话总是 'overwrites' 另一个。

这里是一些简化的代码:

const Component = () => {
  const location = useLocation()

  const [numbers, setNumbers] = useState([1,2,3])

  // say this returns [4,5,6]
  useEffect(()=>{
    fetchOnce().then(newNumbers => setNumbers([...numbers, newNumbers]))
  }, [])

  // say this returns [7,8,9]
  useEffect(()=>{
    fetchMultiple().then(newNumbers => setNumbers([...numbers, newNumbers]))
  }, [location])
}

最终结果是 [1,2,3,4,5,6] 或 [1,2,3,7,8,9]。

如何更改它以便正确设置状态? 我应该是 [1,2,3,4,5,6,7,8,9] 或 [1,2,3,7,8,9,4,5,6]。

改用setNumbers的回调形式:

const Component = () => {
  const location = useLocation()

  const [numbers, setNumbers] = useState([1,2,3])

  // say this returns [2,3,4]
  useEffect(()=>{
    fetchOnce().then(newNumbers => setNumbers(numbers =>[...numbers, ...newNumbers]));
  }, [])

  // say this returns [5,6,7]
  useEffect(()=>{
    fetchMultiple().then(newNumbers => setNumbers(numbers => [...numbers, ...newNumbers]))
  }, [location])
}

const { useState, useEffect } = React;
const fetchOnce = () => Promise.resolve([2, 3, 4]);
const fetchMultiple = () => Promise.resolve([5, 6, 7]);
console.error = () => void 0; // suppress key warning, not sure what OP wants for keys

const Component = () => {
  const [numbers, setNumbers] = useState([1,2,3])
  useEffect(()=>{
    fetchOnce().then(newNumbers => setNumbers(numbers =>[...numbers, ...newNumbers]));
  }, [])
  useEffect(()=>{
    fetchMultiple().then(newNumbers => setNumbers(numbers => [...numbers, ...newNumbers]))
  }, [location])
  return (
    <div>
      {numbers.map(number => <div>{number}</div>)}
    </div>
  );
}

ReactDOM.render(<Component />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class="react"></div>