Invalid Hook Call when using useSelector in Functional Component

Viewed 578

I get the error

Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app

Which I do not understand. I am using useSelector() throughout my App without any Problems. And when using it in this component, it breaks. Why is that?

import { useSelector } from "react-redux";

const DrawerContent = (props) => {
  const someVar = useSelector((state) => state.foo.bar);
  return (
    <DrawerContentScrollView {...props}>
      <Foo>{someVar}</Foo>
      <DrawerItemList {...props}>
        <DrawerItem
          label="Kitten"
          onPress={() => props.navigation.navigate("Cat")}
        />
        <DrawerItem
          label="Doggo"
          onPress={() => props.navigation.navigate("Dog")}
        />
      </DrawerItemList>
    </DrawerContentScrollView>
  );
};

<DrawerContent /> is used like this

const DrawerNavigator = () => {
    return <Drawer.Navigator
        drawerContent={props => DrawerContent(props)}>
        <Drawer.Screen name='A' component={TabNavigator} />
        <Drawer.Screen name='B' component={AStack} />
        <Drawer.Screen name='C' component={BStack} />
    </Drawer.Navigator>
}
1 Answers

You're calling DrawerContent like a normal function, not using it as a tag. As a result, DrawerContent will not have life cycle or state, it's just a normal function, return stuff. You need to invoke it by using JSX syntax, then DrawerContent will have life cycle and you can useSelector there.

const DrawerNavigator = () => {
    return <Drawer.Navigator
        drawerContent={props => DrawerContent(props)}>  // This just call DrawerContent as a normal function with no life cycle and state
        <Drawer.Screen name='A' component={TabNavigator} />
        <Drawer.Screen name='B' component={AStack} />
        <Drawer.Screen name='C' component={BStack} />
    </Drawer.Navigator>
}

Solution:

const DrawerNavigator = () => {
    return <Drawer.Navigator
        drawerContent={props => <DrawerContent {...props} />}>  // Now your component has life cycle
        <Drawer.Screen name='A' component={TabNavigator} />
        <Drawer.Screen name='B' component={AStack} />
        <Drawer.Screen name='C' component={BStack} />
    </Drawer.Navigator>
}
Related