So there are a couple of things you need to fix. First of all you should remove your function call from the useState function, you should only perform your side effects inside a useEffect hook see React Docs.
The next thing is whenever you decide to use the dependency array to your useEffect hook you should include all the dependencies of useEffect i.e all the props, state including functions inside your function component that you used inside your useEffect hook. So the Rule of Thumb is Never Lie About Your Dependencies! otherwise you will shoot yourself in the foot.
So the easiest option is to move your getCreditNoteList function inside your useEffect hook and add all the dependencies of your useEffect hook to the dependency array.
export default function NormalList({ customerId }) {
const pageSize = 20;
const [page, setPage] = useState(1)
const [searchString, setSearchString] = useState(null);
const [creditNotes, setCreditNotes] = useState({});
const [ordering, setOrdering] = useState(null);
useEffect(() => {
function getCreditNoteList() {
API.fetchCreditNoteList({
account_id: customerId,
page,
page_size: pageSize,
searchString,
ordering
}).then(data => {
setCreditNotes(data);
});
}
getCreditNoteList(),
// add ALL! dependencies
}, [page, searchString, ordering, pageSize, customerId]))
return (
<> </>
)
}
Second Option
If you want to use the getCreditNoteList function elsewhere and want to keep it outside your useEffect hook you can do that by wrapping your getCreditNoteList logic inside the useCallback hook as shown below and add the function to your dependency array inside your useEffect hook for reasons i mentioned earlier.
export default function NormalList({ customerId }) {
const pageSize = 20;
const [page, setPage] = useState(1)
const [searchString, setSearchString] = useState(null);
const [creditNotes, setCreditNotes] = useState({});
const [ordering, setOrdering] = useState(null);
const getCreditNoteList = useCallback(() => {
API.fetchCreditNoteList({
account_id: customerId,
page,
page_size: pageSize,
searchString,
ordering
}).then(data => {
setCreditNotes(data);
});
// the function only changes when any of these dependencies change
},[page, searchString, ordering, pageSize, customerId])
useEffect(() => {
getCreditNoteList(),
},[getCreditNoteList])
return (
<> </>
)
}
Содержание
- React Error: Rendered more hooks than during the previous render.
- My Solution!!
- useValue throws error — Rendered more hooks than during previous render #1126
- Comments
- Description
- Package versions
- React hooks report error: Rendered fewer hooks/Rendered more hooks
- Rendered more hooks than during the previous render
React Error: Rendered more hooks than during the previous render.
If you’ve ever written React with hooks, chances are, you’ve probably been greeted with this error at one time.
O ne of the things you might want to do when such error occurs is to ensure you are not violating any the rules from the Hooks documentation.
- Call Hooks from React function components.
- Call Hooks from custom Hooks
- Don’t call Hooks from inside a function or a loop.
You might need to note that, there is a difference between
While both can return JSX, the later will be considered a React component and the former wouldn’t.
Well, all of that said. I recently encountered this error and off course the first thing I did was to check where this error was coming from. I was so sure I wasn’t violenting any of the aforementioned rules.
Well in my case I had these snippets where I needed to pass props around and was returning my component as a function.
For some reason, I know not of, returning my component in the form of a function, cause Hooks to be rendered more than necessary. In other to fix this, I had to read up blog posts. The sad thing was, none pointed at a solution that I sought. However, I found one that led me to finding a solution for myself.
My Solution!!
All I had to do at the end of the day was to replace my code with these lines.
Note the difference, I have replaced the function syntax with component syntax. This was the one solution to this problem I had. I hope it helps someone else who might encounter a similar error.
If you found this helpful, please give it some claps, or share so others can find it too.
Источник
useValue throws error — Rendered more hooks than during previous render #1126
Description
I am following this piece of document about how to use useValue in functional component because the dragging stops working after re-rendering in RN 0.62.2 app/react-native-reanimated 1.13/react-native-gesture-handler 1.7. Here is the code before change which runs fine:
Here is with useValue:
However the code above throws error:
Tried the following and the error is the same:
I can’t find more information about value except this one line statement in the document above. Tried useRef and useMemo and the error is the same. What is the right way in function component to reference a value? Code example appreciated!
The hook is declared in method :
Package versions
- React: 16.11
- React Native: 0.62.2
- React Native Reanimated: 1.13.0
The text was updated successfully, but these errors were encountered:
I’m guessing you’re trying to call displayImg conditionally which breaks the method how React handles hooks. useValue is built on top of useRef , so this is problem with usage of hooks and not Reanimated.
Please provide full code defining and using useValue .
Closing until more info is given.
jakub-gonet , here is the code for function displayImg . Sorry it is long and a bit messy. I put a few lines for helping reading. Many thanks.
Here is how the displayImg gets called in switch :
You’re doing exactly this (conditional render of the hooks) in the line where you have case 1 : you’re calling displayImg as a function. In order to fix this, you should use it as a component —
After converting displayImg to function component, useValue is working.
In app, there are dragX, dragY, offsetX, offsetY, transX, transY, gesState, scale defined for gesture handling. Currently useValue only applied to dragX and dragY . What are the other variables which needs to be useValued for preserving state after re-rendering?
There is another use case which requires reset of all state and this is when uploading new images in DisplayImages which triggers re-rendering. User shall be able to drag and sort again after new images have been uploaded. Sorting only changes image order in data array and uploading increase the number of images in the data array.
By rule of thumb, you should reuse every Value with useValue() to prevent resetting state. Every other animated node should be reused as well, but that’s more like perf optimization, it doesn’t affect the correctness of the code.
Источник
React hooks report error: Rendered fewer hooks/Rendered more hooks
This is used during project development
Rendered more hooks than during the previous render
Before describing the actual situation of the project, let s take a look at one by one. Hell Local
Of course, I’m just giving an example, after all we use
Huh. cough. close to the subject, now we revise
Rendered more than last time
So let me take a look at how it is rendered more than the last time. First of all, the program rendering is
At this time due to
Then we modified the gender
But the program reported an error, and the final rendering result failed to be displayed normally. At this point, we found:
Indeed more than last time, more
What is going on here? Let’s take a look at the documents mentioned in the error message:
Only Call Hooks at the Top Level
Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls. (If you’re curious, we’ll explain this in depth below.)
Call only at the top
Do not call in loops, conditions or nested functions
Источник
When you are working with React Hooks, you may see the error: Uncaught Invariant Violation: Rendered more hooks than during the previous render. In this article, we will show you how to fix this article.
If we conditionally call a hook or return before all of the hooks have finished, we get the error “Rendered more hooks than during the last render”. Move all hooks to the top level of the function component and avoid using hooks within conditions to fix the problem.
Error
Uncaught Invariant Violation: Rendered more hooks than during the previous render.
Let’s take an example of how the error occurs and how to fix it.
Example 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import React, {useEffect, useState} from ‘react’; function App() { const [counter, setCounter] = useState(0); // Error: Rendered more hooks than during the previous render. if (counter > 0) { // Calling React hook conditionally useEffect(() => { console.log(‘hello world’); }); } return ( <div> <button onClick={() => setCounter(counter + 1)}>toggle loading</button> <h1>Hello world</h1> </div> ); } export default App; |
Solution:
Because React hooks can only be invoked at the top level, we must relocate the condition within the hook to fix the issue.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import React, {useEffect, useState} from ‘react’; function App() { const [counter, setCounter] = useState(0); // hook is called at top level (not conditionally) useEffect(() => { if (counter > 0) { console.log(‘hello world’); } }); return ( <div> <button onClick={() => setCounter(counter + 1)}>toggle loading</button> <h1>Hello world</h1> </div> ); } export default App; |
Example 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import React, {useState} from ‘react’; function App() { const [counter, setCounter] = useState(0); // this returns before second hook runs if condition is met if (counter > 0) { return <h2>Returning early</h2>; } // Error because hook is called conditionally const [color, setColor] = useState(‘salmon’); return ( <div> <button onClick={() => setCounter(counter + 1)}>toggle loading</button> <h1>Hello world</h1> </div> ); } export default App; |
Solution:
To fix the issue, we must shift all hooks to the component’s top level, above any circumstances that can result in a return value.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import React, {useState} from ‘react’; export default function App() { const [counter, setCounter] = useState(0); const [color, setColor] = useState(‘salmon’); // condition that may return early must be below all hooks if (counter > 0) { return <h2>Returning early</h2>; } return ( <div> <button onClick={() => setCounter(counter + 1)}>toggle loading</button> <h1>Hello world</h1> </div> ); } export default App; |
Conclusion
- Call hooks only at the top level.
- Calling hooks inside of loops, conditions, or nested functions is not recommended.
- Use hooks first, before any early returns, in the top level of your React method.
- Only call hooks from React function components or from custom hooks.
I hope you find this article helpful.
Thank you for reading. Happy Coding..!! 🙂
If you found value in this article,
you can support us by buying me a coffee! ☕
I am trying to use useEffect in the if condition but I am facing the following error: Uncaught Invariant Violation: Rendered more hooks than during the previous render in Reactjs. In this Exerror article, We are going to learn about How to reproduce this error and we will discuss All Possible Solutions Let’s Get Started with This Article.
Contents
- How Uncaught Invariant Violation: Rendered more hooks than during the previous render Error Occurs?
- How To Solve Uncaught Invariant Violation: Rendered more hooks than during the previous render Error?
- Solution 1: Move Condition into useEffect
- Solution 2: React Hook Calling Rule
- Conclusion
I am trying to use useEffect in the if condition but I am facing the following error.
Uncaught Invariant Violation: Rendered more hooks than during the previous render
Here is my code
import {useState} from 'react';
export default function App() {
const [votes, setVotes] = useState(0);
if (votes > 0) {
useEffect(() => {
console.log('Up Vote Is Bigger Than 0');
});
}
return (
<div>
<button onClick={setVotes(votes + 1)}>Vote Up</button>
<h1>UpVotes: {votes}</h1>
</div>
);
}
So here I am writing all the possible solutions that I have tried to resolve this error.
How To Solve Uncaught Invariant Violation: Rendered more hooks than during the previous render Error?
- How To Solve Uncaught Invariant Violation: Rendered more hooks than during the previous render Error?
To Solve Uncaught Invariant Violation: Rendered more hooks than during the previous render Error We Cannot run UseEffect Conditionally And that’s Why This error Occurs. You Just have to Move Your Condition into useEffect and then Your error will be resolved. Here in Above Code, I Was Using useEffect in the if Condition and that is Causing this error So I Just Moved my If Condition in the useEffect, and Then My Error was resolved.
- Uncaught Invariant Violation: Rendered more hooks than during the previous render
To Solve Uncaught Invariant Violation: Rendered more hooks than during the previous render Error We Cannot run UseEffect Conditionally And that’s Why This error Occurs. You Just have to Move Your Condition into useEffect and then Your error will be resolved. Here in Above Code, I Was Using useEffect in the if Condition and that is Causing this error So I Just Moved my If Condition in the useEffect, and Then My Error was resolved.
Solution 1: Move Condition into useEffect
We Cannot run UseEffect Conditionally And that’s Why This error Occurs. You Just have to Move Your Condition into useEffect and then Your error will be resolved. Just like Below Code.
import {useState} from 'react';
export default function App() {
const [votes, setVotes] = useState(0);
useEffect(() => {
if (votes > 0) {
console.log('Up Vote Is Bigger Than 0');
}
});
return (
<div>
<button onClick={setVotes(votes + 1)}>Vote Up</button>
<h1>UpVotes: {votes}</h1>
</div>
);
}
Here in Above Code, I Was Using useEffect in the if Condition and that is Causing this error So I Just Moved my If Condition in the useEffect, and Then My Error was resolved.
Solution 2: React Hook Calling Rule
Here are some Rules for calling hooks.
- Don’t call Hooks inside loops, conditions, or nested functions
- Only Call Hooks from React Functions
- Call Hooks from React function components.
- Call Hooks from custom Hooks
Conclusion
It’s all About this error. I hope We Have solved Your error. Comment below Your thoughts and your queries. Also, Comment below which solution worked for you?
Also, Read
- Invariant Violation: Too many re-renders. React limits the number of renders to prevent an infinite loop
- Failed to load config “react-app” to extend from
- How to Set port in next.js
- npm ERR! code ENOENT npm ERR! syscall open
- How to update all dependencies in package.json to the latest version
jakub-gonet
, here is the code for function displayImg
. Sorry it is long and a bit messy. I put a few lines for helping reading. Many thanks.
function displayImg (img_source, width, ht, index, modalWidth, modalHt, dataLen, sortFn) {
const aniIndex= new Value(index);
const aniGridPR = new Value(gridPerRow);
const dragX = useRef(new Value(0)).current; //<<==here is the code with useRef/useValue. Tried one line only. Same error for both
const dragY = new Value(0);
const offsetX = new Value(0);
const offsetY = new Value(0);
const state = new Value(-1);
const scale = new Value(1);
var gridPerRow;
console.log("image width : ", width);
console.log("image ht : ", ht);
if (dataLen <= 4 && dataLen > 1) {
gridPerRow = 2;
} else if (dataLen > 4) {
gridPerRow = 3;
} else {
gridPerRow = 1;
};
function onDrop ([x, y, indx, gridPR]) {
var jump_y=0, jump_x=0, new_index, percentage;
//jump_row
jump_y = y>0 ? Math.floor(y/ht) : -Math.floor(-y/ht);
percentage = Math.abs((y%ht)/ht);
//console.log("row percentage : ", percentage);
if (percentage >= 0.3) (y>0 ? jump_y++ : jump_y--); //count if Y overlap 30% or more
//jump col
jump_x = x>0 ? Math.floor(x/width) : -Math.floor(-x/width);
percentage = Math.abs((x%width)/width);
if (percentage >= 0.3) (x>0 ? jump_x++ : jump_x--); //count if X overlap 30% or more
new_index = indx + jump_y*gridPR + jump_x
console.log("new index : ", new_index);
if (new_index != indx) {
sortFn(indx, new_index); //<<==sortFn is a method passed in from calling component to sort images after dragging.
};
};
if (img_source && img_source!==[] && img_source!=={}) {
if (dataLen == 1) { //<<==one image and no dragging but zooming.
const scale = new Value(1);
function onGestureStateChange() {
//handle scaling. not yet implemented
};
let scaleStyle = {
transform:[
{ perspective: 500 },
{
scale : scale
}
]
};
return (
<><PinchGestureHandler onHandlerStateChange={onGestureStateChange}> //<<==allow to zoom in image
<Animated.View style={scaleStyle}>
<GridImage
img_source={img_source}
width={width}
ht={ht}
index={index}
modalWidth={modalWidth}
modalHt={modalHt}
/>
<ModalImage
img_source={img_source}
modalWidth={modalWidth}
modalHt={modalHt}
index={index}
/>
</Animated.View>
</PinchGestureHandler>
</>
);
} else { //<<==when multiple images presented
console.log("ani code");
const addX = add(offsetX, dragX);
const addY = add(offsetY, dragY);
const transX = cond(eq(state, State.ACTIVE), addX);
const transY = cond(eq(state, State.ACTIVE), addY,
cond(eq(state, State.END),
cond(or(greaterOrEq(abs(divide(dragX,new Value(width))), new Value(0.3)), greaterOrEq(abs(divide(dragY,new Value(ht))), new Value(0.3))),
call([addX, addY, aniIndex, aniGridPR], onDrop))
) //<<==when image is moved 30% or more on X or Y, then call method onDrop. otherwise no move (image back to its original position)
);
const handleGesture = event([
{
nativeEvent: {
translationX: dragX,
translationY: dragY,
state,
},
},
]);
let aniStyle = {
transform:[
{ translateX : transX },
{ translateY : transY },
]
};
let scaleStyle = {
transform:[
{ perspective: 500 },
{
scale : scale
}
]
};
return (
<>
<PanGestureHandler
onGestureEvent={handleGesture}
onHandlerStateChange={handleGesture}
minPointers={1}
maxPointers={1}>
<Animated.View style={[aniStyle ]}>
<GridImage
img_source={img_source}
width={width}
ht={ht}
index={index}
/>
</Animated.View>
</PanGestureHandler>
<ModalImage
img_source={img_source}
modalWidth={modalWidth}
modalHt={modalHt}
index={index}
/> //<<==show full image in modal
</>
);
};
} else {
return null;
};
};
Here is how the displayImg
gets called in switch
:
switch(len) { //len is the number of images in array
case 0:
return;
case 1:
return (
<>
{displayImg(picPath(pics[0]), screen_width*full, screen_width*full, 0, screen_width, pics[0].height*(screen_width/pics[0].width), len)}
</>
);
case 2: //<<==2-4 image will be displayed in 2 rows
/* console.log("pics before return : ", pics);
return (
<Grid style={{position:"absolute", paddingTop:0,paddingLeft:0}}>
<Row style={styles.row}>
{pics.map((item, index) => {
return (displayImg(picPath(item), screen_width*half, screen_width*half, index, screen_width, item.height*(screen_width/item.width), len, move))
})}
</Row>
</Grid>
); */
case 3:
case 4:
return (
<Grid style={{position:"absolute", paddingTop:0,paddingLeft:0}}>
{pics.map((item, index) => {
if (index%2===0) {
if (pics[index+1]) {
return (
<Row style={styles.row}>
{displayImg(picPath(item), screen_width*half, screen_width*half, index, screen_width, item.height*(screen_width/item.width), len, move)}
{displayImg(picPath(pics[index+1]), screen_width*half, screen_width*half, index+1, screen_width, pics[index+1].height*(screen_width/pics[index+1].width), len, move)}
</Row>
)} else {
return (
<Row style={styles.row}>
{displayImg(picPath(item), screen_width*half, screen_width*half, index, screen_width, item.height*(screen_width/item.width), len, move)}
</Row>
)};
}
})}
</Grid>
);
default: //<<==more than 4 images will be displayed in 3 rows with 3 columns
return (
<Grid style={{position:"absolute", paddingTop:0,paddingLeft:0}}>
{pics.map((item, index) => {
if (index%3===0) {
if (pics[index+2]) {
return (
<Row style={styles.row}>
{displayImg(picPath(item), screen_width*oneThird, screen_width*oneThird, index, screen_width, item.height*(screen_width/item.width), len, move)}
{displayImg(picPath(pics[index+1]), screen_width*oneThird, screen_width*oneThird, index+1, screen_width, pics[index+1].height*(screen_width/pics[index+1].width), len, move)}
{displayImg(picPath(pics[index+2]), screen_width*oneThird, screen_width*oneThird, index+2, screen_width, pics[index+2].height*(screen_width/pics[index+2].width), len, move)}
</Row>
)} else if (pics[index+1]) {
return (
<Row style={styles.row}>
{displayImg(picPath(item), screen_width*oneThird, screen_width*oneThird, index, screen_width, item.height*(screen_width/item.width), len, move)}
{displayImg(picPath(pics[index+1]), screen_width*oneThird, screen_width*oneThird, index+1, screen_width, pics[index+1].height*(screen_width/pics[index+1].width), len, move)}
</Row>
)} else if (!pics[index+1]) {
return (
<Row style={styles.row}>
{displayImg(picPath(item), screen_width*oneThird, screen_width*oneThird, index, screen_width, item.height*(screen_width/item.width), len, move)}
</Row>
)} else {
return null;
};
}
})}
</Grid>
);
};