I'm trying to abstract my fetch out to a hook in my expo react native app. The fetch must be able to do POST method. I started out by trying to use and then modify the useHook() effect found at https://usehooks-ts.com/react-hook/use-fetch. It caused too many re-renders. So in searching Stack Overflow I found this article that recommended that I do it as a function. Since, I anticipate almost every fetch request is going to be a POST and done with a submit, that looked like a good idea. But it is still giving me too many re-renders. Then I found this article that said to do it with a useCallBack. Still no success...
Here is the hook I'm trying to use:
import { useCallback, useState } from "react";import { FetchQuery } from "../interfaces/FetchQuery";interface State<T> { data?: T; error: Error | string | null; fetchData: any;}const useFetch2 = <T = unknown,>(): State<T> => { const [data, setData] = useState<T>(); const [error, setError] = useState<Error | null>(null); const fetchData = useCallback(async (query: FetchQuery) => { const { url, options } = query; if (!url) return; const response = await fetch(url, options); const data = await response.json(); if (data.error) { setData(undefined); setError(data.error); } else { setData(data); setError(null); } }, []); return { fetchData, data, error };};export default useFetch2;
This is the component calling the code (right now it assigns all of the data to the error field so I can validate the data coming back):
export default function AdminLogin() { // screen controls const [err, setErr] = useState<Error | string | undefined>(); // form controls const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); // fetch information // const [fetchQuery, setFetchQuery] = useState<FetchQuery>({}); const { fetchData, data, error } = useFetch2<User>(); if (error) { setErr(error); } if (data?.user) { setErr(JSON.stringify(data.user)); } const handleSignIn = async () => { const options = { method: "POST", headers: { Accept: "application/json","Content-Type": "application/json","Cache-control": "no-cache", }, body: JSON.stringify({ email, password }), }; const url = BASE_API +"users/login"; // setFetchQuery({ url, options }); <-- attempted to use this with useEffect fetchData({ url, options }); }; // useEffect(() => { // fetchData(); // }, [fetchQuery]); return (<View style={styles.container}><Text style={styles.msg}>Maps can only be edited by Administers.</Text><View style={styles.controlGroup}><Text style={styles.UnPw}>Email</Text><TextInput style={styles.txInput} keyboardType="email-address" placeholder="Email" value={email} onChangeText={(value) => setEmail(value)} /></View><View style={styles.controlGroup}><Text style={styles.UnPw}>Password</Text><TextInput style={styles.txInput} maxLength={18} placeholder="Password" value={password} onChangeText={(value) => setPassword(value)} secureTextEntry /></View><TouchableOpacity onPress={handleSignIn}><Text>Sign in</Text></TouchableOpacity> {/* {status === "loading" && <Text>Loading...</Text>} */} {err && (<><Text style={styles.errText}>Error:</Text><Text style={styles.errText}>{err}</Text></> )}</View> );} const styles = StyleSheet.create({});
Adding some console.log
commands does show that states are continually updating after the fetch command, but I don't understand why nor how to fix it.