Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Invalid hook call React Native FlatList Navigation

I’m making a notes app in React Native and trying to make it so I can click on a note in a FlatList to edit it. I’m using react-router-native for this. I get an Error when clicking on any FlatList item. I know that this error has been asked on stack overflow before but the answers are all for class components, whereas I’m using functional components.

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. 
import { FlatList, Pressable, StyleSheet, View } from "react-native"
import { useNavigate } from "react-router-native"
import theme from "../theme"
import Text from "./Text"

const styles = StyleSheet.create({
  separator: {
    height: 10,
    backgroundColor: theme.colors.background,
  },
  item: {
    padding: 8,
    backgroundColor: "white",
  },
})
const ItemSeparator = () => <View style={styles.separator} />

const renderItem = ({ item }) => (
  <View style={styles.item}>
    <Pressable onPress={() => useNavigate(`/${item.id}`)}>
      <Text fontWeight="bold" fontSize="subheading">
        {item.title}
      </Text>
      <Text>{item.body}</Text>
    </Pressable>
  </View>
)

const NoteList = ({ notes }) => {
  return (
    <FlatList
      data={notes}
      ItemSeparatorComponent={ItemSeparator}
      renderItem={renderItem}
      keyExtractor={(item) => item.id}
    />
  )
}

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

useNavigate is a React hook and can only be called by a React function component or other custom React hook. It cannot be called in nested functions/callbacks.

Move the useNavigate hook call to the NoteList component and refactor the renderItem callback to curry a passed navigate function.

const ItemSeparator = () => <View style={styles.separator} />;

const renderItem = (navigate) => ({ item }) => (
  <View style={styles.item}>
    <Pressable onPress={() => navigate(`/${item.id}`)}>
      <Text fontWeight="bold" fontSize="subheading">
        {item.title}
      </Text>
      <Text>{item.body}</Text>
    </Pressable>
  </View>
);

const NoteList = ({ notes }) => {
  const navigate = useNavigate(); // <-- hook called in React function

  return (
    <FlatList
      data={notes}
      ItemSeparatorComponent={ItemSeparator}
      renderItem={renderItem(navigate)} // <-- pass navigate
      keyExtractor={(item) => item.id}
    />
  );
};

Alternatively you could move the renderItem function declaration into the NoteList component so the navigate function is just closed over in callback scope.

const ItemSeparator = () => <View style={styles.separator} />;

const NoteList = ({ notes }) => {
  const navigate = useNavigate();

  const renderItem = ({ item }) => (
    <View style={styles.item}>
      <Pressable onPress={() => navigate(`/${item.id}`)}>
        <Text fontWeight="bold" fontSize="subheading">
          {item.title}
        </Text>
        <Text>{item.body}</Text>
      </Pressable>
    </View>
  );

  return (
    <FlatList
      data={notes}
      ItemSeparatorComponent={ItemSeparator}
      renderItem={renderItem}
      keyExtractor={(item) => item.id}
    />
  );
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading