使用 Axios 和 useReducer 获取异步数据的 React 自定义 Hook 时状态不更新
State Not Updating when Consuming React Custom Hook that Uses Axios with useReducer to Get Async Data
我的应用程序 returns 在使用我的 useFetch 自定义挂钩时出现“null 不是对象”渲染错误使用 axios 获取异步数据。 status、error 和 data 属性保持默认值不变,我不知道问题是否与我改变数据的方式有关,或者我没有正确返回或使用它们。
// 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>
);
}
您的数据响应为空。您可以通过说 { uri : tweet?.data.avatar }
来避免获得 undefind,但我认为您应该首先通过执行 const { data, error , loading } = useFetch(url)
来正确解构您的 useFetch。如果那没有帮助,那么您应该 require(`${tweet?.data.avatar}`)
。希望有所帮助。不过你的代码真的很脆弱,你应该先调试为什么你返回 null...
刚刚解决了这个问题,事实证明我只需要做 return state
而不是 return [state]
因为将它包装在数组中会导致状态陈旧。
所以现在我只是像这样使用自定义挂钩:const { status, error, data: tweet } = useFetch(...);
而不是:const [{ status, error, data: tweet }] = useFetch(...);
我的应用程序 returns 在使用我的 useFetch 自定义挂钩时出现“null 不是对象”渲染错误使用 axios 获取异步数据。 status、error 和 data 属性保持默认值不变,我不知道问题是否与我改变数据的方式有关,或者我没有正确返回或使用它们。
// 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>
);
}
您的数据响应为空。您可以通过说 { uri : tweet?.data.avatar }
来避免获得 undefind,但我认为您应该首先通过执行 const { data, error , loading } = useFetch(url)
来正确解构您的 useFetch。如果那没有帮助,那么您应该 require(`${tweet?.data.avatar}`)
。希望有所帮助。不过你的代码真的很脆弱,你应该先调试为什么你返回 null...
刚刚解决了这个问题,事实证明我只需要做 return state
而不是 return [state]
因为将它包装在数组中会导致状态陈旧。
所以现在我只是像这样使用自定义挂钩:const { status, error, data: tweet } = useFetch(...);
而不是:const [{ status, error, data: tweet }] = useFetch(...);