搜尋

首頁  >  問答  >  主體

未捕獲的不變違規:與先前的渲染相比,渲染了更多的鉤子

我有一個看起來像這樣的元件(非常簡化的版本):

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>;
}

當我載入使用此元件的頁面時,出現此錯誤:Uncaught Invariant Violation: Rendered more hooks than during the previous render. 我試圖找到此錯誤的解釋,但是我的搜尋沒有返回結果。

當我稍微修改元件時:

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>;
}

我不再收到該錯誤。是因為我在 renderResults 傳回的 jsx 中包含了 setState 函數嗎?如果能夠解釋該修復為何有效,那就太好了。

P粉477369269P粉477369269243 天前563

全部回覆(2)我來回復

  • P粉729198207

    P粉7291982072024-03-26 10:59:40

    我也遇到了同樣的問題。我正在做的事情是這樣的:

    const Table = (listings) => {
    
        const {isLoading} = useSelector(state => state.tableReducer);
    
        if(isLoading){
            return <h1>Loading...</h1>
        }
    
        useEffect(() => {
           console.log("Run something")
        }, [])
    
        return (<table>{listings}</table>)
    }

    我認為發生的情況是在第一次渲染時,元件提前返回並且 useEffect 沒有運行。當 isLoading 狀態更改時,useEffect 運行,我收到錯誤 - 鉤子渲染的次數比之前的渲染次數多。

    一個簡單的更改就解決了這個問題:

    const Table = (listings) => {
        
        const {isLoading} = useSelector(state => state.tableReducer);
            
        useEffect(() => {
            console.log("Run something")
        }, [])
        
        if(isLoading){
            return <h1>Loading...</h1>
        }
        return (<table>{listings}</table>)
    }

    回覆
    0
  • P粉448346289

    P粉4483462892024-03-26 10:39:49

    該修復之所以有效,是因為第一個程式碼範例(出錯的程式碼)呼叫了onClick 內的函數,而第二個程式碼範例(有效的程式碼範例)則將函數傳遞給了onClick。區別在於那些非常重要的括號,在 JavaScript 中意味著「呼叫此程式碼」。

    這樣想:在第一個程式碼範例中,每次渲染 component 時,都會呼叫 renderResults。每次發生這種情況時,都會呼叫 setAllResultsVisible(!allResultsVisible),而不是等待點擊。由於 React 按照自己的時間表執行渲染,因此無法確定會發生多少次。

    來自 React 文件:

    React 處理事件文檔

    注意:在沙箱中執行第一個程式碼範例時,我無法獲得確切的錯誤訊息。我的錯誤涉及無限循環。也許較新版本的 React 會產生所描述的錯誤?

    回覆
    0
  • 取消回覆