React 组件不使用 Spread 运算符重新渲染
我已经尝试过该网站上的其他解决方案,但我不确定为什么这不起作用。每次按下按钮时,我都会从服务器收到响应。响应非常顺利,每次按下按钮时我都能看到它。我从服务器接收一个对象数组,并且使用 useState 挂钩来设置变量的状态以跟踪数组中的对象。但是,该组件不会重新渲染。有趣的是,如果我添加一个 console.log 语句来查看状态变量的内容,然后保存页面,我可以看到状态变量已正确更新。但该组件仍然不会重新渲染。相关代码在这里:
import React, { useEffect, useState } from "react";
import { StyleSheet, View, TouchableOpacity, Alert } from "react-native";
import tailwind from "tailwind-rn";
import colors from "../config/colors";
import useAuth from "../hooks/useAuth";
import Screen from "../components/Screen";
import AppText from "../components/AppText";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { getData } from "../hooks/useCache";
import { useIsFocused } from "@react-navigation/native";
import ListScreen from "./ListScreen";
const ProfileScreen = () => {
const { logout, user } = useAuth();
const [likes, setLikes] = useState("");
const [completed, setCompleted] = useState("");
const [responseJson, setResponseJson] = useState(null);
const isFocused = useIsFocused();
useEffect(() => {
const likesFunc = async() => {
setLikes(await getData("likes"));
setCompleted(await getData("eventsCompleted"));
try {
const response = await fetch(
"server url here",
{
headers: { Authorization: "Bearer " + user.idToken },
}
);
const responseJson = await response.json();
setLikes(responseJson.likes);
setCompleted(responseJson.eventsCompleted);
} catch {
Alert.alert("There has been an error processing your profile");
}
}
likesFunc();
}, []);
//get voted events
//run when questionsLeft is 0 to save num of calls
useEffect(() => {
const eventFunction = async() => {
try {
const response = await fetch(
"server url here",
{
headers: { Authorization: "Bearer " + user.idToken },
}
)
const res = await response.json();
setResponseJson([...res]);
} catch (error) {
Alert.alert(
"An error has occurred loading your questions. Close the app and try again."
);
console.log(error);
}
}
eventFunction();
}, [isFocused]);
return (
<Screen style={styles.bg}>
<View
style={[
tailwind("w-full flex-row py-4 justify-center items-center top-0"),
{ justifyContent: "space-between" },
]}
>
<AppText style={{ color: colors.white, fontSize: 30, marginLeft: 5 }}>
Hello, {user.displayName.split(" ")[0]}
</AppText>
<TouchableOpacity
style={styles.logoutButton}
onPress={() => {
Alert.alert("Log Out", "Are you sure you want to log out?", [
{
text: "Yes",
style: "destructive",
onPress: logout,
},
{
text: "Cancel",
style: "cancel",
},
]);
}}
>
<MaterialCommunityIcons
name="logout-variant"
size={25}
color={colors.primary}
/>
</TouchableOpacity>
</View>
<View
style={tailwind("w-full h-1/5 justify-center items-center")}
>
<View
style={[
tailwind("w-full flex-row p-10 justify-center"),
{ justifyContent: "space-between" },
]}
>
<View style={tailwind("justify-center items-center")}>
<AppText style={{ textDecorationLine: "underline" }}>
Total Likes
</AppText>
<AppText style={{ paddingVertical: 10 }}>{likes}</AppText>
</View>
<View style={tailwind("justify-center items-center")}>
<AppText style={{ textDecorationLine: "underline" }}>
Completed
</AppText>
<AppText style={{ paddingVertical: 10 }}>{completed}</AppText>
</View>
</View>
</View>
<View
style={tailwind("w-full h-4/5 flex-1 items-center")}
>
{responseJson == null ?
<AppText style={tailwind("mt-10")}>
Select events on the "Discover" page!
</AppText>
:
<ListScreen caller={{"sender": "profile", "json": responseJson}}/>
}
</View>
</Screen>
);
};
export default ProfileScreen;
const styles = StyleSheet.create({
logoutButton: {
color: colors.white,
paddingTop: 20,
paddingRight: 10,
},
bg: {
flex: 1,
backgroundColor: colors.black,
},
});
更新:如果我连续两次设置状态,它会起作用:
setResponseJson(null);
setResponseJson([...res]);
但是,这有点错误并且不是最佳的。让我认为这仍然是一个参考问题,但我不确定为什么扩展运算符技术不能解决这个问题。
I've tried other solutions on this site, but I am not sure why this is not working. I have a response I am getting from a server each time a button is pressed. The response comes through fine and I am able to see it each time the button is pressed. I am receiving an array of objects from the server, and I am using the useState hook to set the state of a variable to keep track of the objects in the array. However, the component does not re render. Interestingly, if I add a console.log statement to see the contents of the state variable and then save the page, I can see that the state variable was updated properly. The component still does not re render though. The relevant code is here:
import React, { useEffect, useState } from "react";
import { StyleSheet, View, TouchableOpacity, Alert } from "react-native";
import tailwind from "tailwind-rn";
import colors from "../config/colors";
import useAuth from "../hooks/useAuth";
import Screen from "../components/Screen";
import AppText from "../components/AppText";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { getData } from "../hooks/useCache";
import { useIsFocused } from "@react-navigation/native";
import ListScreen from "./ListScreen";
const ProfileScreen = () => {
const { logout, user } = useAuth();
const [likes, setLikes] = useState("");
const [completed, setCompleted] = useState("");
const [responseJson, setResponseJson] = useState(null);
const isFocused = useIsFocused();
useEffect(() => {
const likesFunc = async() => {
setLikes(await getData("likes"));
setCompleted(await getData("eventsCompleted"));
try {
const response = await fetch(
"server url here",
{
headers: { Authorization: "Bearer " + user.idToken },
}
);
const responseJson = await response.json();
setLikes(responseJson.likes);
setCompleted(responseJson.eventsCompleted);
} catch {
Alert.alert("There has been an error processing your profile");
}
}
likesFunc();
}, []);
//get voted events
//run when questionsLeft is 0 to save num of calls
useEffect(() => {
const eventFunction = async() => {
try {
const response = await fetch(
"server url here",
{
headers: { Authorization: "Bearer " + user.idToken },
}
)
const res = await response.json();
setResponseJson([...res]);
} catch (error) {
Alert.alert(
"An error has occurred loading your questions. Close the app and try again."
);
console.log(error);
}
}
eventFunction();
}, [isFocused]);
return (
<Screen style={styles.bg}>
<View
style={[
tailwind("w-full flex-row py-4 justify-center items-center top-0"),
{ justifyContent: "space-between" },
]}
>
<AppText style={{ color: colors.white, fontSize: 30, marginLeft: 5 }}>
Hello, {user.displayName.split(" ")[0]}
</AppText>
<TouchableOpacity
style={styles.logoutButton}
onPress={() => {
Alert.alert("Log Out", "Are you sure you want to log out?", [
{
text: "Yes",
style: "destructive",
onPress: logout,
},
{
text: "Cancel",
style: "cancel",
},
]);
}}
>
<MaterialCommunityIcons
name="logout-variant"
size={25}
color={colors.primary}
/>
</TouchableOpacity>
</View>
<View
style={tailwind("w-full h-1/5 justify-center items-center")}
>
<View
style={[
tailwind("w-full flex-row p-10 justify-center"),
{ justifyContent: "space-between" },
]}
>
<View style={tailwind("justify-center items-center")}>
<AppText style={{ textDecorationLine: "underline" }}>
Total Likes
</AppText>
<AppText style={{ paddingVertical: 10 }}>{likes}</AppText>
</View>
<View style={tailwind("justify-center items-center")}>
<AppText style={{ textDecorationLine: "underline" }}>
Completed
</AppText>
<AppText style={{ paddingVertical: 10 }}>{completed}</AppText>
</View>
</View>
</View>
<View
style={tailwind("w-full h-4/5 flex-1 items-center")}
>
{responseJson == null ?
<AppText style={tailwind("mt-10")}>
Select events on the "Discover" page!
</AppText>
:
<ListScreen caller={{"sender": "profile", "json": responseJson}}/>
}
</View>
</Screen>
);
};
export default ProfileScreen;
const styles = StyleSheet.create({
logoutButton: {
color: colors.white,
paddingTop: 20,
paddingRight: 10,
},
bg: {
flex: 1,
backgroundColor: colors.black,
},
});
Update: If I set the state twice in a row, it works:
setResponseJson(null);
setResponseJson([...res]);
However, this is somewhat buggy and not optimal. Leads me to think it still is a reference issue, but I am not sure why the spread operator technique does not fix this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的代码中有三件事是错误/奇怪的。不确定它会解决您的问题,但它们是:
1-不要将异步函数传递给
useEffect
。相反,在内部创建一个异步函数并调用它:2- 您正在从 api 调用接收一个对象数组,那么为什么要传播它呢?它会导致您的状态内出现多个对象,这似乎不对。只需按原样传递您的
res
或按您想要的格式设置即可。3-您将
async/await
模式与.then
混合在一起。使用异步函数并等待结果:或者仅使用
.then
:Three things are wrong/weird in your code. Not sure it will fix your problem but here are they :
1- Do not pass an async function to the
useEffect
. Instead, create an async function inside and call it :2- You are receiving an array of objects from your api call, so why do you want to spread it ? It would lead to multiple objects inside your state, which doesn't seems right. Just pass your
res
in your state as is or format it as you want.3- You are mixing
async/await
pattern with the.then
. Either use an async func and await the result :or only use the
.then
: