3

I am developing an e-commerce application using React Native and I am trying to use useState in the drawerContent and it tells me this

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 Hooks
  3. You might have more than one copy of React in the same app

Thank you in advance for your answers.

Here's the code

import React, { useState } from 'react'
import { View, Text, TouchableOpacity, FlatList, StyleSheet, StatusBar } from 'react-native'
import IonIcons from "react-native-vector-icons/Ionicons"
import { categories } from '../../../services/DataTest'
import DrawerSearch from './DrawerSearch'
import DrawerItem from './DrawerItem'

export default function DrawerContent (props) {
    const [search, setSearch] = useState("");

    return (
        <View>
            <TouchableOpacity
                style={styles.customDrawerTouch}
            >
                <View style={styles.backButtonRow}>
                    <IonIcons
                        name="ios-arrow-back"
                        size={25}
                        style={styles.customDrawerIcon}
                        color="#666666"
                    />
                    <Text style={{ color: '#666666' }}>Back to Components</Text>
                </View>
            </TouchableOpacity>
            <DrawerSearch value={search} setValue={setSearch}/>
            <FlatList
                data={categories}
                keyExtractor={(item, index) => index.toString()}
                renderItem={DrawerItem}
            />
        </View>
    );
}

const styles = StyleSheet.create({
    customDrawerTouch: {
        marginTop: StatusBar.currentHeight,
        paddingLeft: 13,
        paddingTop: 15,
    },
    customDrawerIcon: {
        paddingRight: 10
    },
    backButtonRow: {
        flexDirection: 'row',
        alignItems: 'center',
        paddingBottom: 17,
        paddingLeft: 3,
        borderBottomColor: '#F0F0F0',
        borderBottomWidth: 1,
    },
});

I'm using this component here

import * as React from 'react';
import { View, StyleSheet, StatusBar } from 'react-native';
import { createDrawerNavigator } from '@react-navigation/drawer';
import HeaderCategorie from '../../components/categories/index/HeaderCategorie';
import SearchBar from '../../components/home/index/SearchBar';
import DrawerContent from '../../components/categories/index/DrawerContent';

const Drawer = createDrawerNavigator();

function CategoriesScreen({ navigation }) {

    return (
        <View style={styles.container}>
            <HeaderCategorie navigation={navigation}/>
            <View style={styles.headerSearch}>
                <SearchBar />
            </View>
            
        </View>
    )
}

export default function Categories() {
    return (
        <Drawer.Navigator initialRouteName="Categories"
            drawerContent={DrawerContent}
            screenOptions={{headerShown:false}}
        >
            <Drawer.Screen name="Categories" component={CategoriesScreen} />
        </Drawer.Navigator>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: "flex-start",
        alignItems: "center",
        marginTop: StatusBar.currentHeight,
    },
    headerSearch: {
        marginVertical:10
    },
    headerSearchText: {
        fontWeight:"bold",
        fontSize:35,
        marginLeft:20,
        marginVertical:15,
    }
});
Moistbobo
  • 2,342
  • 1
  • 7
  • 16

1 Answers1

2

Reason: By using drawerContent={DrawerContent}, you are actually passing the reference of the DrawerContent function, which ends up breaking rules of hooks.

So to resolve this, change the following line:

     <Drawer.Navigator initialRouteName="Categories"
            drawerContent={DrawerContent}
            screenOptions={{headerShown:false}}
        >

to this

     <Drawer.Navigator initialRouteName="Categories"
            drawerContent={(props)=> <DrawerContent {...props}/>} // here
            screenOptions={{headerShown:false}}
        >

demo snack

Moistbobo
  • 2,342
  • 1
  • 7
  • 16
  • Thank you for your help, I understood my mistake :) – Adrian Mong Sep 18 '21 at 18:27
  • but i thought `DrawerContent` is a function component which hasn't been invoked yet. How's the change would make it work? – windmaomao Sep 18 '21 at 19:47
  • @windmaomao I had a look at the issues in the react-navigation repo and found [this](https://github.com/react-navigation/react-navigation/issues/7725#issuecomment-595795543). From my understanding, It seems like the reason is that `drawerContent` has to be a render function, not an actual function component. But I can't find any official documentation that differentiates the two. – Moistbobo Sep 18 '21 at 20:08
  • @Moistbobo, thanks i missed that part `(props)`, so it's a render function. Man, maybe this is how router uses as well. Makes sense, thank you very much!! – windmaomao Sep 18 '21 at 22:11