Skip to content
Advertisement

State Not Updating when Consuming React Custom Hook that Uses Axios with useReducer to Get Async Data

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.

Render Error

API

// 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(...);

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement