我有一個(gè)看起來(lái)像這樣的組件(非常簡(jiǎn)化的版本):
const component = (props: PropTypes) => { const [allResultsVisible, setAllResultsVisible] = useState(false); const renderResults = () => { return ( <section> <p onClick={ setAllResultsVisible(!allResultsVisible) }> More results v </p> { allResultsVisible && <section className="entity-block--hidden-results"> ... </section> } </section> ); }; return <div>{ renderResults() }</div>; }
當(dāng)我加載使用此組件的頁(yè)面時(shí),出現(xiàn)此錯(cuò)誤:Uncaught Invariant Violation: Rendered more hooks than during the previous render.
我試圖找到此錯(cuò)誤的解釋?zhuān)俏业乃阉鳑](méi)有返回結(jié)果。
當(dāng)我稍微修改組件時(shí):
const component = (props: PropTypes) => { const [allResultsVisible, setAllResultsVisible] = useState(false); const handleToggle = () => { setAllResultsVisible(!allResultsVisible); } const renderResults = () => { return ( <section> <p onClick={ handleToggle }> More results v </p> { allResultsVisible && <section className="entity-block--hidden-results"> ... </section> } </section> ); }; return <div>{ renderResults() }</div>; }
我不再收到該錯(cuò)誤。是因?yàn)槲以?renderResults
返回的 jsx 中包含了 setState
函數(shù)嗎?如果能夠解釋該修復(fù)為何有效,那就太好了。
我也遇到了同樣的問(wèn)題。我正在做的事情是這樣的:
const Table = (listings) => { const {isLoading} = useSelector(state => state.tableReducer); if(isLoading){ return <h1>Loading...</h1> } useEffect(() => { console.log("Run something") }, []) return (<table>{listings}</table>) }
我認(rèn)為發(fā)生的情況是在第一次渲染時(shí),組件提前返回并且 useEffect 沒(méi)有運(yùn)行。當(dāng) isLoading 狀態(tài)更改時(shí),useEffect 運(yùn)行,我收到錯(cuò)誤 - 鉤子渲染的次數(shù)比之前的渲染次數(shù)多。
一個(gè)簡(jiǎn)單的更改就解決了這個(gè)問(wèn)題:
const Table = (listings) => { const {isLoading} = useSelector(state => state.tableReducer); useEffect(() => { console.log("Run something") }, []) if(isLoading){ return <h1>Loading...</h1> } return (<table>{listings}</table>) }
該修復(fù)之所以有效,是因?yàn)榈谝粋€(gè)代碼示例(出錯(cuò)的代碼)調(diào)用了 onClick
內(nèi)的函數(shù),而第二個(gè)代碼示例(有效的代碼示例)則將函數(shù)傳遞給了 onClick
。區(qū)別在于那些非常重要的括號(hào),在 JavaScript 中意味著“調(diào)用此代碼”。
這樣想:在第一個(gè)代碼示例中,每次渲染 component
時(shí),都會(huì)調(diào)用 renderResults
。每次發(fā)生這種情況時(shí),都會(huì)調(diào)用 setAllResultsVisible(!allResultsVisible)
,而不是等待單擊。由于 React 按照自己的時(shí)間表執(zhí)行渲染,因此無(wú)法確定會(huì)發(fā)生多少次。
來(lái)自 React 文檔:
注意:在沙箱中運(yùn)行第一個(gè)代碼示例時(shí),我無(wú)法獲得確切的錯(cuò)誤消息。我的錯(cuò)誤涉及無(wú)限循環(huán)。也許較新版本的 React 會(huì)產(chǎn)生所描述的錯(cuò)誤?