我有一个看起来像这样的组件(非常简化的版本):
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>;
}
我不再遇到该错误。是因为我在setState
返回的jsx中包含了renderResults
函数吗?解释一下该修复程序为何起作用,将是很棒的事情。
答案 0 :(得分:7)
我遇到了同样的问题。我正在做的事情是这样的:
const Table = (listings) => {
const {isLoading} = useSelector(state => state.tableReducer);
useEffect(() => {
console.log("Run something")
}, [])
if(isLoading){
return <h1>Loading...</h1>
}
return (<table>{listings}</table>)
}
我认为发生的情况是在第一次渲染时,组件提前返回并且 useEffect 没有运行。当 isLoading 状态改变时,useEffect 运行,我得到错误 - 钩子渲染的次数比之前的渲染次数多。
一个简单的改变修复了它:
fd.c
答案 1 :(得分:2)
该修复程序起作用是因为第一个代码示例(出错的代码)调用onClick
内部的函数,而第二个示例(工作的示例)将函数传递给onClick
。区别在于那些非常重要的括号,在JavaScript中意味着“调用此代码”。
这样想:在第一个代码示例中,每次渲染component
时,都会调用renderResults
。每次发生时,都会调用setAllResultsVisible(!allResultsVisible)
而不是等待单击。由于React按照自己的时间表执行渲染,因此无法确定将发生多少次。
从React文档中:
使用JSX,您可以传递一个函数作为事件处理程序,而不是字符串。
Bitcoin Core BIP39 Specifications
注意:在沙箱中运行第一个代码示例时,我无法获得此确切的错误消息。我的错误是指无限循环。也许是更新版本的React产生了所描述的错误?
答案 2 :(得分:2)
您只需在setAllResultsVisible之前添加() =>
即可更改onlick事件
<p onClick={() => setAllResultsVisible(!allResultsVisible) }>
More results v
</p>
它将完美运行
答案 3 :(得分:2)
即使在完成上述修复后,此错误也有其他一些原因。我在下面写一个针对我的用例。
function Comp(props){return <div>{props.val}</div>}
可以在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
答案 4 :(得分:0)
看到问题可以是React:
在两种情况下,事情都可能像您有一条条件语句调用同一函数一样,该函数从不同的位置返回渲染,就像都包裹在父返回函数中一样:
const parentFunc = () => {
if(case==1)
return function_a();
if (case==2)
return function_b();
}
现在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
}
答案 5 :(得分:0)
问题发生在onClick
的调用setAllResultsVisible
中,它将触发状态更改并在每次渲染时产生结果
onClick={ setAllResultsVisible(!allResultsVisible) }
将其更改为函数调用:
onClick={_ => setAllResultsVisible(!allResultsVisible) }