未捕获的不变违规:与之前的渲染相比,渲染了更多的钩子
P粉477369269
P粉477369269 2024-03-25 16:50:53
0
2
582

我有一个看起来像这样的组件(非常简化的版本):

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粉477369269
P粉477369269

全部回复(2)
P粉729198207

我也遇到了同样的问题。我正在做的事情是这样的:

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>)
}
P粉448346289

该修复之所以有效,是因为第一个代码示例(出错的代码)调用了 onClick 内的函数,而第二个代码示例(有效的代码示例)则将函数传递给了 onClick。区别在于那些非常重要的括号,在 JavaScript 中意味着“调用此代码”。

这样想:在第一个代码示例中,每次渲染 component 时,都会调用 renderResults。每次发生这种情况时,都会调用 setAllResultsVisible(!allResultsVisible),而不是等待单击。由于 React 按照自己的时间表执行渲染,因此无法确定会发生多少次。

来自 React 文档:

React 处理事件文档

注意:在沙箱中运行第一个代码示例时,我无法获得确切的错误消息。我的错误涉及无限循环。也许较新版本的 React 会产生所描述的错误?

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板