Reputation: 79
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
Upvotes: 2
Views: 411
Reputation: 2038
React hooks can't be an async function. So according to this redux workflow:
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
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