Search code examples
reactjsreact-nativereact-hooksreact-native-flatlistreact-component

My react hooks fail when used inside my react component that is deeply nesed into my react application


When I use useHistory hook here ...

import React from 'react';
import {View,Image,StyleSheet, TouchableOpacity} from 'react-native';
import theme from '../theme';
import Text from './Text'
import {useQuery} from '@apollo/react-hooks'
import {GET_REPOSITORY} from '../graphql/queries'
import {useHistory} from 'react-router-native'

const RepositoryItem = (props) => {
    let history = useHistory()
    let item = props.item

    const styles = StyleSheet.create({
        ...
    });

    const reduceToK = (num) => {
        if (num > 999) {
            const thousandsNum = Math.round(num / 1000);
            const remainerNum = Math.round((num % 1000) / 100);
            return `${thousandsNum}.${remainerNum}k`;
        } else return num;
    };

    return (
        <View style={styles.rootContainer}>
            {...}
        </View>
    );
};

export default RepositoryItem;

The application breaks and returns the following error ...

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM)2. You might be breaking the Rules of Hooks3. You might have more than one copy of React in the same app

This component (RepositoryItem) is being used inside another component (RepositoryList) like so ...

import React from 'react';
import { FlatList, View, StyleSheet, Text } from 'react-native';
import RepositoryItem from './RepositoryItem';
// ...


const styles = StyleSheet.create({
  ...
});

const RepositoryList = () => {
  let history = useHistory()
  const repositories = useQuery(GET_REPOSITORIES, {fetchPolicy: 'cache-and-network'});

  if (!repositories.loading) {
    const ItemSeparator = () => <View style={styles.separator} />;
  
    // Get the nodes from the edges array
    const repositoryNodes = repositories.data.repositories && !repositories.loading
      ? repositories.data.repositories.edges.map(edge => edge.node)
      : [];
  
    return (
      <FlatList
        data={repositoryNodes}
        ItemSeparatorComponent={ItemSeparator}
        renderItem={RepositoryItem}
        keyExtractor={repository => repository.fullName}
      />
    );
  } else {
    return (<View><Text>Loading...</Text></View>);
  }

};

export default RepositoryList;

That component is being used in the App component.

My theory is that in react native's FlatList renderItem prop one cannot use hooks.

Any idea what the issue might be here?


Solution

  • You may want to do it this way because renderItem accepts a function.

    <FlatList
            data={repositoryNodes}
            ItemSeparatorComponent={ItemSeparator}
            renderItem={({item}) => <RepositoryItem item={item} />}
            keyExtractor={repository => repository.fullName}
          />