My app returns a “null is not an object” Render Error when consuming the useFetch custom hook that I made to get async data using axios. The status, error, and data properties remains the same with their default values, I don’t know if the problem is related to how I mutate my data or I’m not returning or consuming them properly.
// Axios config import axios from "axios"; const instance = axios.create({ baseURL: "http://10.0.2.2:8000/api", }); export default instance;
// Custom hook import { useReducer, useEffect } from "react"; import axiosConfig from "../axiosConfig"; export default function useFetch(url) { const initialState = { status: "idle", error: null, data: null, }; const [state, dispatch] = useReducer((state, action) => { switch (action.type) { case "FETCHING": return { ...state, status: "fetching" }; case "FETCHED": return { ...state, status: "fetched", data: action.payload }; case "FETCH_ERROR": return { ...state, status: "error", error: action.payload }; default: return state; } }, initialState); useEffect(() => { let cancelRequest = false; if (!url) return; function fetchData() { dispatch({ type: "FETCHING" }); axiosConfig .get(url) .then((response) => { if (cancelRequest) return; dispatch({ type: "FETCHED", payload: response.data }); }) .catch((error) => { if (cancelRequest) return; dispatch({ type: "FETCH_ERROR", payload: error }); }); } fetchData(); return function cleanup() { cancelRequest = true; }; }, [url]); return [state]; }
// Consume custom hook import React from "react"; import { View, Text, StyleSheet, TouchableOpacity, Image, ActivityIndicator, } from "react-native"; import GlobalStyles from "../constants/GlobalStyles"; import { Entypo, EvilIcons } from "@expo/vector-icons"; import format from "date-fns/format"; import useFetch from "../utils/hooks/useFetch"; export default function TweetScreen({ route, navigation }) { const [{ status, error, data: tweet }] = useFetch( `/tweets/${route.params.tweetId}` ); error && console.log(error); function gotoProfile(userId) { navigation.navigate("Profile Screen", { userId }); } return ( <View style={GlobalStyles.container}> {status === "fetching" ? ( <ActivityIndicator size="large" color="#007aff" /> ) : ( <> <View style={[ GlobalStyles.flexRow, GlobalStyles.spaceBetween, styles.tweetContainer, ]} > <TouchableOpacity style={GlobalStyles.flexRow} onPress={() => gotoProfile(tweet.user.id)} > <Image style={styles.avatar} source={{ uri: tweet.user.avatar }} /> </TouchableOpacity> </View> </> )} </View> ); }
Advertisement
Answer
Just solved this thing, turns out I just needed to do return state
instead of return [state]
as wrapping it inside an array causes the state to be stale.
So now I just consume the custom hook like this: const { status, error, data: tweet } = useFetch(...);
Instead of: const [{ status, error, data: tweet }] = useFetch(...);