React报错Uncaught Invariant Violation: Rendered more hooks than during the previous render.

发布于 2020-07-31 00:00:00

在一个函数组件加载的时候报错:

Uncaught Invariant Violation: Rendered more hooks than during the previous render.

翻译一下的意思是: 比上次渲染时渲染了更多的钩子。 下面是报错后的一段提示

react-dom.development.js?61bb:506 Warning: React has detected a change in the order of Hooks called by ReportEditor. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://fb.me/rules-of-hooks

   Previous render            Next render
   ------------------------------------------------------
1. useContext                 useContext
2. useEffect                  useEffect
3. useContext                 useContext
4. useEffect                  useEffect
5. useContext                 useContext
6. useEffect                  useEffect
7. useContext                 useContext
8. useEffect                  useEffect
9. useContext                 useContext
10. useEffect                 useEffect
11. useContext                useContext
12. useEffect                 useEffect
13. useContext                useContext
14. useEffect                 useEffect
15. useContext                useContext
16. useEffect                 useEffect
17. useContext                useContext
18. useRef                    useRef
19. useEffect                 useEffect
20. useContext                useContext
21. useReducer                useReducer
22. useMemo                   useMemo
23. useRef                    useRef
24. useRef                    useRef
25. useRef                    useRef
26. useLayoutEffect           useLayoutEffect
27. useLayoutEffect           useLayoutEffect
28. useContext                useContext
29. useReducer                useReducer
30. useMemo                   useMemo
31. useRef                    useRef
32. useRef                    useRef
33. useRef                    useRef
34. useLayoutEffect           useLayoutEffect
35. useLayoutEffect           useLayoutEffect
36. useContext                useContext
37. useReducer                useReducer
38. useMemo                   useMemo
39. useRef                    useRef
40. useRef                    useRef
41. useRef                    useRef
42. useLayoutEffect           useLayoutEffect
43. useLayoutEffect           useLayoutEffect
44. undefined                 useCallback
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

结合代码想到可能是因为提前返回造成的两次绑定的usecallback数量不一致,下面是代码

useEffect(() => {
    dispatch(ReportActions.getReportConfig(reportId))
  }, [])

  const currentReport = useSelector(makeSelectCurrentDisplay())
  const currentLayerList = useSelector(makeSelectCurrentLayerList())
  const layersOperationInfo = useSelector(makeSelectCurrentLayersOperationInfo())

  if(!currentReport){
    return <></>
  }

  const commandLayers = useCallback((operation) => {
    ...
  }, [])

  const selectionChange = useCallback(
    (layerId: number, checked: boolean, exclusive: boolean) => {
      .....
    },
    []
  )


  return (
    <div style={{ position: 'fixed', top: 48, bottom: 0, left: 0, right: 0, display: 'flex' }}>
      <ReportAdaptor>
            ....
      </Layout>
      </ReportAdaptor>
    </div>
  )
}

因为通过

if(!currentReport){
     return <>
   }

这句代码执行的时候提前返回了,导致第一次执行没有执行后面的usecallback,第二次执行的时候有callback,两次callback数量不一致导致了这个错误,后面把currentReport是否为空的判断放在return之前&&usecallback定义之后就可以了。