未捕获的不变违规:比上一次渲染期间渲染的钩子更多

tim*_*hym 7 javascript reactjs react-hooks

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

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>;
}
Run Code Online (Sandbox Code Playgroud)

加载使用此组件的页面时,出现以下错误: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>;
}
Run Code Online (Sandbox Code Playgroud)

我不再收到该错误。是因为我将setState函数包含在返回的jsx中renderResults吗?解释为什么修复程序会很高兴。

Jak*_*rth 31

该修复程序有效,因为第一个代码示例(出错的代码示例)调用 内部的函数onClick,而第二个(工作中的)将函数传递给onClick。区别在于那些非常重要的括号,它们在 JavaScript 中的意思是“调用此代码”。

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

来自 React 文档:

使用 JSX,您可以传递一个函数作为事件处理程序,而不是一个字符串。

React 处理事件文档

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

  • 是的,我犯了一个严重的错误。我总是在 onClicks 中混淆 `() =&gt; function()` 和 `function()` 。 (2认同)

Ert*_*ani 19

您可以在 setAllResultsVisible() =>之前简单地更改您的 onlick 事件添加

<p onClick={() => setAllResultsVisible(!allResultsVisible) }> 
    More results v
</p>
Run Code Online (Sandbox Code Playgroud)

它会完美地工作


Rah*_*hah 13

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

const Table = (listings) => {

    const {isLoading} = useSelector(state => state.tableReducer);

    if(isLoading){
        return <h1>Loading...</h1>
    }

    useEffect(() => {
       console.log("Run something")
    }, [])

    return (<table>{listings}</table>)
}
Run Code Online (Sandbox Code Playgroud)

我认为发生的事情是在第一次渲染时,组件提前返回并且 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>)
}
Run Code Online (Sandbox Code Playgroud)

  • 遇到这个错误,我的问题是一样的,我在钩子上方有一个“return”语句 (2认同)

Aks*_*ain 12

即使在上述修复之后,仍有一些其他原因导致此错误。我在下面写了一个发生在我身上的用例。

function Comp(props){return <div>{props.val}</div>}
Run Code Online (Sandbox Code Playgroud)

该组件在jsx中可以通过以下方式调用:

1. <Comp val={3} /> // works well
2. { Comp({val:3}) } // throws uncaught invariant violation error, at least it throw in my case, may be there were other factors, but changing back to first way removed that problem
Run Code Online (Sandbox Code Playgroud)


ims*_*i17 10

查看问题可以是 React :

  1. 渲染的钩子比之前的渲染更少。
  2. 渲染了比之前渲染更多的钩子。

在这两种情况下,事情就像你有一个条件语句调用同一个函数,该函数从不同的地方返回渲染,就像都包装在父返回函数中一样:

const parentFunc = () => {
    if(case==1)
        return function_a();
    if (case==2)
        return function_b();
}
Run Code Online (Sandbox Code Playgroud)

现在 function_a() 可以是一个创建两个或一个钩子的函数,假设 useStyle() 或其他任何东西

function_b() 可以是不创建钩子的函数。

现在,当parentFunc返回function_a()渲染一个钩子而function_b()渲染不渲染钩子时,react会告诉你,从同一个渲染函数返回两个不同的渲染,一个带有两个或一个钩子,另一个带有一个钩子,这种差异导致错误。错误是

渲染的钩子更少。而且这个错误是相当明显的。

当情况颠倒并且 function_b() 返回第一个条件原因时,react 会告诉您从同一个渲染函数返回了不同的渲染,并且错误将是 。

渲染了比之前渲染更多的钩子。

现在,解决方案:

更改代码流程,例如创建 function_ab() ,这将确保在该函数中呈现所有正在使用的挂钩:

const function_ab = () => {
    if(case==1)
         return (<div></div>) //or whatever
    if(case==2)
         return (<div>I am 2 </div>) //or whatever
}
Run Code Online (Sandbox Code Playgroud)


Mis*_*oto 6

出现此错误的一个可能原因是使用

\n
Component() // error\n<Component /> // good\n
Run Code Online (Sandbox Code Playgroud)\n

这是解释\xef\xbc\x9a

\n

如果直接调用组件函数,它只是一个返回 JSX 的函数(没有状态,没有效果)。里面的钩子不能正常工作,可能会被认为是父组件的钩子。如果使用<Component />,就相当于执行了 React.createElement ,里面的钩子就会按预期工作。

\n