React 组件不使用 Spread 运算符重新渲染

发布于 2025-01-14 09:28:11 字数 5012 浏览 1 评论 0原文

我已经尝试过该网站上的其他解决方案,但我不确定为什么这不起作用。每次按下按钮时,我都会从服务器收到响应。响应非常顺利,每次按下按钮时我都能看到它。我从服务器接收一个对象数组,并且使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

简单 2025-01-21 09:28:11

您的代码中有三件事是错误/奇怪的。不确定它会解决您的问题,但它们是:

1-不要将异步函数传递给useEffect。相反,在内部创建一个异步函数并调用它:

useEffect(() => {
  const myFunc = async => {...};
  myFunc();
},[]);

2- 您正在从 api 调用接收一个对象数组,那么为什么要传播它呢?它会导致您的状态内出现多个对象,这似乎不对。只需按原样传递您的 res 或按您想要的格式设置即可。

3-您将 async/await 模式与 .then 混合在一起。使用异步函数并等待结果:

const myFunc = async () => {
  const resPromise = await fetch(...);
  const json = await resPromise.json();
  ...
}

或者仅使用 .then

  const myFunc = () => {
  fetch(...)
    .then(data => data.json())
    .then(json => ...);
  ...
}

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 :

useEffect(() => {
  const myFunc = async => {...};
  myFunc();
},[]);

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 :

const myFunc = async () => {
  const resPromise = await fetch(...);
  const json = await resPromise.json();
  ...
}

or only use the .then:

  const myFunc = () => {
  fetch(...)
    .then(data => data.json())
    .then(json => ...);
  ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文