disabled
disabled

Reputation: 79

Invalid hook call React

https://reactjs.org/docs/hooks-custom.html Building your own Hooks lets you extract component logic into reusable functions. Thats what I want to do: extract my component logic into reusable functions for other components.

My functional component:

//React
import React from 'react';
import { FlatList, View, Text, StyleSheet } from 'react-native';
//Local
import UserPreview from './UserPreview';
import defaultContainer from '../../shared/styles/defaultContainer';
import useFetchUsers from './../../../handler/useFetchUsers';

export default function UserList(props) {
    const { users } = props;
    const dispatch = useDispatch();
    //State
    const [isLoading, setIsLoading] = React.useState(false);
    const [error, setError] = React.useState(null);

    return (
        <View style={defaultContainer}>
            <FlatList
                data={users}
                keyExtractor={(item) => item.id}
                renderItem={({ item }) => <UserPreview user={item} />}
                ListEmptyComponent={() => <Text style={styles.listEmpty}>Keine Benutzer gefunden!</Text>}
                ItemSeparatorComponent={() => <View style={styles.listSeperator} />}
                onRefresh={useFetchUsers}
                refreshing={isLoading}
                contentContainerStyle={styles.container}
            />
        </View>
    );
}

my reusable function:

import React from 'react';
import * as userActions from '../store/actions/user';
import { useDispatch } from 'react-redux';

export default async function useFetchUsers() {
    const [error, setError] = React.useState(null);
    const dispatch = useDispatch();
    const [isLoading, setIsLoading] = React.useState(false);

    console.log('StartupScreen: User laden');
    setIsLoading(true);
    setError(null);
    try {
        await dispatch(userActions.fetchUsers());
        console.log('StartupScreen: User erfolgreich geladen');
    } catch (err) {
        setError(err.message);
    }
    setIsLoading(false);
}

How should I use my function in the onRefresh prop in my Userlist? I'm getting this error: Invalid hook call enter image description here

Upvotes: 2

Views: 411

Answers (2)

Ali Torki
Ali Torki

Reputation: 2038

React hooks can't be an async function. So according to this redux workflow: enter image description here

You have to dispatch fetch user's action and then your loading and error states should be in your reducer and if you have any side effect manager such as redux-saga alongside your redux, you have to call all HTTP methods right there and your components just should dispatch and present the results. The other way is to call and fetch users into your hook and put them into your redux store via an action which you dispatch. In this way, loading and error can be in your hook(in your local hook state, not into the redux-store).

So let's try this code(I've implemented the second way):

import React from 'react';
import * as userActions from '../store/actions/user';
import { useDispatch } from 'react-redux';

export default function useFetchUsers() {
    const [error, setError] = React.useState(null);
    const dispatch = useDispatch();
    const [isLoading, setIsLoading] = React.useState(false);
    
    React.useEffect(() => {
      (async () => {
          console.log('StartupScreen: User laden');
          setIsLoading(true);
          setError(null);
          try {
              const res = await fetchUsers();

              dispatch(setUsers(res.data));
              console.log('StartupScreen: User erfolgreich geladen');
              setIsLoading(false);
          } catch (err) {
              setIsLoading(false);
              setError(err.message);
          }
      })()
    }, [])
}

Upvotes: 1

UjinT34
UjinT34

Reputation: 4997

You are using useFetchUsers as a callback. Rules of Hooks forbid this.

useFetchUsers should return some function that can be used as callback:

export default function useFetchUsers() {
    const [error, setError] = React.useState(null);
    const dispatch = useDispatch();
    const [isLoading, setIsLoading] = React.useState(false);

    return async function() {
        console.log('StartupScreen: User laden');
        setIsLoading(true);
        setError(null);
        try {
            await dispatch(userActions.fetchUsers());
            console.log('StartupScreen: User erfolgreich geladen');
        } catch (err) {
            setError(err.message);
        }
        setIsLoading(false);
    }
}


function UserList(props) {

    ...

    const handleRefresh = useFetchUsers();

    ...

    return <FlatList onRefresh={handleRefresh} />;
}

Upvotes: 2

Related Questions