У меня есть компонент, который выглядит так (очень упрощенная версия):
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? Было бы здорово иметь объяснение, почему исправление работает.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Исправление работает, потому что первый образец кода (с ошибкой) вызывает функцию внутри onClick, а второй (рабочий) передает функцию onClick. Разница заключается в тех самых важных скобках, которые в JavaScript означают «вызвать этот код».
Подумайте об этом так: в первом примере кода каждый раз, когда рендерится component, вызывается renderResults. Каждый раз, когда это происходит, вызывается setAllResultsVisible(!allResultsVisible), а не ожидание щелчка. Поскольку React выполняет рендеринг по собственному расписанию, неизвестно, сколько раз это произойдет.
Из документов React:
With JSX you pass a function as the event handler, rather than a string.
Документы по обработке событий React
Примечание. Мне не удалось получить это точное сообщение об ошибке при запуске первого примера кода в песочнице. Моя ошибка относится к бесконечному циклу. Может быть, более свежая версия React выдает описанную ошибку?
Вы можете просто изменить добавление события onclick () => перед setAllResultsVisible.
<p onClick = {() => setAllResultsVisible(!allResultsVisible) }>
More results v
</p>
и он будет работать отлично
Даже после исправлений, описанных выше, есть несколько других причин этой ошибки. Я пишу ниже один случай использования, который произошел со мной.
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
Посмотреть вопрос можно 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(), не рендерящий хук, тогда реакция сообщит вам, что из одной и той же функции рендеринга были возвращены два разных рендера, один с двумя или одним хуком, а другой с одним хуком, это несоответствие приводит к Ошибка. Ошибка
less hooks were rendered. And the error is quite obvious.
Когда случаи меняются местами и функция_b() возвращается первой причиной условных выражений, тогда реакция сообщит вам, что из одной и той же функции рендеринга были возвращены разные рендеры, и будет ошибка.
Rendered more hooks than previous render.
Теперь решение:
Измените поток кода, например, создайте функцию function_ab(), которая обеспечит визуализацию всех используемых хуков и в этой функции:
const function_ab = () => {
if (case==1)
return (<div></div>) //or whatever
if (case==2)
return (<div>I am 2 </div>) //or whatever
}
Проблема заключается в onClick, поскольку setAllResultsVisible вызывается, это вызывает изменение состояния и результат при каждом рендеринге.
onClick = { setAllResultsVisible(!allResultsVisible) }
Вместо этого измените это на вызов функции:
onClick = {_ => setAllResultsVisible(!allResultsVisible) }
Я столкнулся с той же проблемой. Я делал что-то вроде этого:
const Table = (listings) => {
const {isLoading} = useSelector(state => state.tableReducer);
if (isLoading){
return <h1>Loading...</h1>
}
useEffect(() => {
console.info("Run something")
}, [])
return (<table>{listings}</table>)
}
Я думаю, что произошло то, что при первом рендеринге компонент вернулся раньше, а useEffect не запустился. Когда состояние isLoading изменилось, запустился useEffect, и я получил ошибку — хук отрендерился больше раз, чем предыдущий рендер.
Простое изменение исправило это:
const Table = (listings) => {
const {isLoading} = useSelector(state => state.tableReducer);
useEffect(() => {
console.info("Run something")
}, [])
if (isLoading){
return <h1>Loading...</h1>
}
return (<table>{listings}</table>)
}
Правильно, большая ошибка с моей стороны. Я постоянно путаю
() => function()иfunction()в onClicks.