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.
JavaScript
x
10
10
1
// Axios config
2
3
import axios from "axios";
4
5
const instance = axios.create({
6
baseURL: "http://10.0.2.2:8000/api",
7
});
8
9
export default instance;
10
JavaScript
1
54
54
1
// Custom hook
2
3
import { useReducer, useEffect } from "react";
4
import axiosConfig from "../axiosConfig";
5
6
export default function useFetch(url) {
7
const initialState = {
8
status: "idle",
9
error: null,
10
data: null,
11
};
12
13
const [state, dispatch] = useReducer((state, action) => {
14
switch (action.type) {
15
case "FETCHING":
16
return { state, status: "fetching" };
17
case "FETCHED":
18
return { state, status: "fetched", data: action.payload };
19
case "FETCH_ERROR":
20
return { state, status: "error", error: action.payload };
21
default:
22
return state;
23
}
24
}, initialState);
25
26
useEffect(() => {
27
let cancelRequest = false;
28
if (!url) return;
29
30
function fetchData() {
31
dispatch({ type: "FETCHING" });
32
33
axiosConfig
34
.get(url)
35
.then((response) => {
36
if (cancelRequest) return;
37
dispatch({ type: "FETCHED", payload: response.data });
38
})
39
.catch((error) => {
40
if (cancelRequest) return;
41
dispatch({ type: "FETCH_ERROR", payload: error });
42
});
43
}
44
45
fetchData();
46
47
return function cleanup() {
48
cancelRequest = true;
49
};
50
}, [url]);
51
52
return [state];
53
}
54
JavaScript
1
56
56
1
// Consume custom hook
2
3
import React from "react";
4
import {
5
View,
6
Text,
7
StyleSheet,
8
TouchableOpacity,
9
Image,
10
ActivityIndicator,
11
} from "react-native";
12
import GlobalStyles from "../constants/GlobalStyles";
13
import { Entypo, EvilIcons } from "@expo/vector-icons";
14
import format from "date-fns/format";
15
import useFetch from "../utils/hooks/useFetch";
16
17
export default function TweetScreen({ route, navigation }) {
18
const [{ status, error, data: tweet }] = useFetch(
19
`/tweets/${route.params.tweetId}`
20
);
21
22
error && console.log(error);
23
24
function gotoProfile(userId) {
25
navigation.navigate("Profile Screen", { userId });
26
}
27
28
return (
29
<View style={GlobalStyles.container}>
30
{status === "fetching" ? (
31
<ActivityIndicator size="large" color="#007aff" />
32
) : (
33
<>
34
<View
35
style={[
36
GlobalStyles.flexRow,
37
GlobalStyles.spaceBetween,
38
styles.tweetContainer,
39
]}
40
>
41
<TouchableOpacity
42
style={GlobalStyles.flexRow}
43
onPress={() => gotoProfile(tweet.user.id)}
44
>
45
<Image
46
style={styles.avatar}
47
source={{ uri: tweet.user.avatar }}
48
/>
49
</TouchableOpacity>
50
</View>
51
</>
52
)}
53
</View>
54
);
55
}
56
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(...);