使用 GraphQL 在 NextJS 中渲染比之前渲染更多的钩子

时间:2021-01-25 17:43:09

标签: reactjs graphql react-hooks next.js

我将导航栏放在我的 _app.js 中,所以我不需要将它插入到每个组件中。我的问题是,在我登录后,它输出错误 Rendered more hooks than during the previous render. 并将其指向 useQuery(GETCARTDATA

请在这里检查我的代码

const App = ({ Component, pageProps }) => {
    const token = getToken()
    const [isPopUpShow, setPopUpShow] = useState(false)
    const [cartStateData, setCartStateData] = useState([])
    const [isCartOpen, setCartOpen] = useState(false)
    let cartDetailsData
    
    if (token) {
      // eslint-disable-next-line react-hooks/rules-of-hooks
      cartDetailsData = useLazyQuery(GETCARTDATA, {
        variables: {
          page: 1
        },
      })
      // eslint-disable-next-line react-hooks/rules-of-hooks
      useMemo(() => {
        const cartData = get(cartDetailsData.data, 'findCartDetails.orders') || []
        const cartItems = []
        if (cartData.length) {
          cartData.map(
            itm =>
              itm.lineItems.length &&
              itm.lineItems.map(item => cartItems.push(item))
          )
        }
        setCartStateData(cartItems)
      }, [cartDetailsData.data])
    }
  
    return (
      <>
        <div className="app-outer">
          {token ? (
            <ShowroomHeader
              isPopUpShow={isPopUpShow}
              setPopUpShow={setPopUpShow}
              cartStateData={cartStateData}
              cartDetailsData={cartDetailsData}
              token={token}
            />
          ) : (
            <Navbar />
          )}
        </div>
  
        <div className="main">
          <Component {...pageProps} />
        </div>

      </>
    )
  }
  
  export default withApollo(App)

1 个答案:

答案 0 :(得分:1)

正如@xadmn 所提到的,您正在有条件地渲染钩子,而 React 期望每次渲染的钩子调用次数相同。

您需要删除 if 语句并将条件移动到 useEffect 钩子内,使用 useLazyQuery 的返回函数从那里执行查询。您还可以将 useMemo 代码移至 onCompleted 回调,因为这取决于查询结果。

const App = ({ Component, pageProps }) => {
    const token = getToken()
    const [isPopUpShow, setPopUpShow] = useState(false)
    const [cartStateData, setCartStateData] = useState([])
    const [isCartOpen, setCartOpen] = useState(false)

    const [getCardData, cartDetailsData] = useLazyQuery(GETCARTDATA, {
        onCompleted: (data) => {
            const cartData = get(data, 'findCartDetails.orders') || []
            const cartItems = []
            if (cartData.length) {
                cartData.map(
                    itm =>
                        itm.lineItems.length &&
                        itm.lineItems.map(item => cartItems.push(item))
                )
            }
            setCartStateData(cartItems)
        }
    })

    useEffect(() => {
        if (token) {
            getCardData({ variables: { page: 1 } })
        }
    }, [token])
  
    return (
        // Your JSX here
    )
}