为什么我的 useEffect 中仍然有陈旧数据?

jha*_*amm 6 javascript reactjs react-hooks

我的useEffect正在运行,但一旦完成,它就不会更新我的组件的状态。它总是显示以前的渲染。我以为我已经添加了所有适当的依赖项,但它仍然给了我陈旧的数据。这是我的钩子:

export default function useSort(items, sortKey, sortAscending) {
  let [sorted, setSorted] = useState(items);

  useEffect(() => {
    let sortedItems = sortKey ? items.sort((a, b) => {
      if (!a[sortKey] && b[sortKey]) return sortAscending ? -1 : 1;
      if (a[sortKey] && !b[sortKey]) return sortAscending ? 1 : -1;
      if (a[sortKey] > b[sortKey]) return sortAscending ? 1 : -1;
      if (a[sortKey] < b[sortKey]) return sortAscending ? -1 : 1;
      return 0;
    }) : items;
     setSorted(sortedItems);
  }, [items, sortKey, sortAscending]);

  return sorted;
}
Run Code Online (Sandbox Code Playgroud)

这是我正在使用它的组件:

const SearchResults = ({ columns, searchResults, sortAscending, sortKey }) => {
  const dispatch = useDispatch();
  let sorted = useSort(searchResults, sortKey, sortAscending);

  return sorted.map((searchResult, index) => {
    return ( ... )
  }
Run Code Online (Sandbox Code Playgroud)

SearchResult呈现,但是当我尝试对结果进行排序时(取决于我单击的列标题),useEffect代码会运行。排序后,SearchResult永远不会重新渲染以显示更改。

我如何错误地使用钩子?正确的用法是什么?

Mhm*_*z_A 4

JavaScript 中的数组是reference类型;当当前值和之前的值不同时,会setState导致组件重新渲染;与原始类型不同,引用类型仅在其引用发生变化时才会标记为已更改(即浅比较)。在这种情况下,当您就地改变数组时,从浅比较的角度来看,前一个值和下一个值将是相同的;这就像在已经存在的setState(2)情况下打电话一样;和解将忽略这一点。人们已经在评论中提到,如果您返回新数组(新引用),那就可以修复它;顺便说一句,请查看下面的代码片段,了解此处发生的问题的具体展示:state2

ReactDOM.render(<Test/>, document.getElementById("root"))

function Test(){
    const [array, setArray] = React.useState([2,3,4,5]);
    const renderCounter = React.useRef(0);
    
    function mutateInPlace(e){
        renderCounter.current++;
        // some random in-place mutations
        array[1] = 4;
        array[2] = 11;
        array.sort((a,b)=>a-b);
        setArray(array);
    }
    
    function mutateOutOfPlace(e) {
        renderCounter.current++;
        // creating a new array
        let arrayCopy = array.slice(0);
        setArray(arrayCopy);
    }
    
    console.log("re-rendered");
    return (
        <div>
            {renderCounter.current}
            <br/>
            <button onClick={mutateInPlace}>mutate in-place</button>
            <button onClick={mutateOutOfPlace}>mutate out-of-place</button>
        </div>
    );
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>

<div id="root"></div>
Run Code Online (Sandbox Code Playgroud)