hellomello
hellomello

Reputation: 8597

React Native: Rendered more hooks than during the previous render error

I'm getting the Rendered more hooks than during the previous render error in my react native application in this screen:

const HomeScreen = props => {
  const [refreshing, setRefreshing] = useState(false);

  if (props.data.loading) { // error shows its located here
    return <Text>Loading...</Text>; 
  }

  const onRefresh = useCallback(() => {
    setRefreshing(true);

    wait(2000).then(() => setRefreshing(false));
  }, [refreshing]);

  return (
    <View style={styles.container}>
      <FlatList
        data={props.data.sample}
        renderItem={({item}) => <Card {...item} user={props.data.user} />}
        keyExtractor={item => item._id}
        refreshControl={
          <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
        }
      />
    </View>
  );
};

But when I move the useState below the if-statement:

const HomeScreen = props => {

  if (props.data.loading) { // error shows its located here
    return <Text>Loading...</Text>; 
  }

  // moved here, change in the order of hooks...
  const [refreshing, setRefreshing] = useState(false); 

  const onRefresh = useCallback(() => {
    setRefreshing(true);

    wait(2000).then(() => setRefreshing(false));
  }, [refreshing]);

I get a Warning:

Warning: React has detected a change in the order of Hooks called by "HomeScreen". This will lead to bugs and errors if not fixed...

I get this error when my app hot reloads, but then when I Dismiss the warning and then force reload it doesn't appear. I just want to make sure that moving this below the if-statement is okay.

Also, I don't know why moving the useState will fix the original error message of rerendering?

Upvotes: 3

Views: 4602

Answers (1)

giotskhada
giotskhada

Reputation: 2452

Well, the error is obvious. Only useState is called when loading is true, and both useState and useCallback are called when it's not, so react complains about the number of hooks being inconsistent. The fix is most likely a fluke. This time no hooks are called when loading is true, and both of them are rendered when it's not. React's source code probably doesn't make the "number of hooks rendered" check if that number is zero initially, hence no error.

As the warning tells you, conditionally calling hooks (writing a return statement before any hook) is a bad idea. It might not break you app in this particular instance, but it's overall a bad practice. The hooks are called on every render and react needs to keep track of them properly.

I would put all the hooks (in this case both useState and useCallback) BEFORE the conditional return. I don't see any reasons not to.

Upvotes: 3

Related Questions