You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中其他state更新时如何避免指定useState重置为初始值

问题根因
  • 代码存在状态冗余问题:likebutton、likebuttoncolor、postlikes三个状态完全可以从item和user信息派生得到,不需要单独声明为useState状态,冗余状态没有和item同步更新,就会出现你以为的「重置」问题。
  • 直接修改状态对象:代码里found ? (item.userlike = true) : false属于直接修改useState定义的item状态,不符合React状态不可变的原则,会导致状态更新不可预测。
  • 接口请求返回新的item数据后,没有补充userlike字段就直接setitem,新的item对象没有用户是否点赞的标记,导致后续计算异常。
修复方案
  1. 移除三个冗余的点赞相关状态,直接在渲染时根据item动态计算即可
  2. 遵循状态不可变原则,所有对item的修改都通过setitem传入新对象实现,不要直接修改原item
  3. 接口请求拿到最新的帖子数据后,先判断当前用户是否点赞,补充userlike字段后再更新item状态
  4. 点赞点击逻辑里直接更新item状态,派生属性会自动同步,不需要手动修改多个状态
核心修改后代码
import React, { useState, useEffect } from "react";
import {
  Image,
  StyleSheet,
  TouchableOpacity,
  Text,
  View,
  SafeAreaView,
  Alert
} from "react-native";

import { EvilIcons } from "@expo/vector-icons";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import axios from "axios";
import AsyncStorage from "@react-native-async-storage/async-storage";

import url from "../url";

const Handlenewspost = ({ navigation }) => {
  const items = navigation.getParam("item");
  const user = navigation.getParam("user");
  const functionforoffset = navigation.getParam("functionforoffset");
  // 仅保留item一个核心状态,初始化时就补充userlike字段
  const [item, setitem] = useState(() => {
    const initItem = {...items};
    const found = initItem.like?.find(element => element.username === user.username) ?? false;
    initItem.userlike = !!found;
    return initItem;
  });

  // 点赞相关属性直接派生,不需要存state
  const likebutton = item.userlike ? "heart" : "heart-outline";
  const likebuttoncolor = item.userlike ? "red" : "black";
  const postlikes = item.likes;

  useEffect(() => {
    axios
      .get(url + "post/byid/" + items._id)
      .then((response) => {
        // 拿到新数据后先补充userlike字段
        const newItem = {...response.data};
        const found = newItem.like?.find(element => element.username === user.username) ?? false;
        newItem.userlike = !!found;
        setitem(newItem);
      })
      .catch((err) => {
        console.log(err);
        console.log(err?.response?.data?.error);
        Alert.alert("Something went wrong", err?.response?.data?.error, [
          { text: "OK", onPress: () => console.log("OK Pressed") },
        ]);
      });
  }, []);

  const onpresshandle = async (item) => {
    const userToken = await AsyncStorage.getItem("userToken");
    const id = item._id;
    const token = userToken;
    functionforoffset();
    axios
      .post(url + "post/like", { token, id })
      .catch((err) => {
        console.log(err);
        console.log(err?.response?.data?.error);
        Alert.alert("Something went wrong", err?.response?.data?.error, [
          { text: "OK", onPress: () => console.log("OK Pressed") },
        ]);
      });
  };

  // 点赞点击逻辑简化
  const handleLikeClick = () => {
    setitem(prev => {
      const newItem = {...prev};
      newItem.userlike = !newItem.userlike;
      newItem.likes = newItem.userlike ? newItem.likes + 1 : newItem.likes - 1;
      return newItem;
    });
    onpresshandle(item);
  };

  function checkcaption(caption) {
    if (caption != "") {
      return (
        <SafeAreaView style={styles.safe}>
          <View
            style={[
              styles.root,
              { flexDirection: "row", alignItems: "center" },
            ]}
          >
            <Text style={[styles.textStyle, { fontSize: 15, marginLeft: 0 }]}>
              {item.caption}
            </Text>
          </View>
        </SafeAreaView>
      );
    } else {
      return <View></View>;
    }
  }

  return (
    <>
      <SafeAreaView style={{ flex: 1 }}>
        <View style={styles.container}>
          <View style={styles.card}>
            <View style={styles.cardheader}>
              {item.profileimage ? (
                <Image
                  source={{ uri: url + "filename/" + item.profileimage }}
                  style={{
                    marginLeft: 16,
                    marginRight: 8,
                    height: 40,
                    width: 40,
                    borderRadius: 100,
                  }}
                ></Image>
              ) : (
                <Image
                  source={require("../../assets/localbazilogo2.jpeg")}
                  style={[
                    styles.profileimage,
                    { marginLeft: 16, marginRight: 5 },
                  ]}
                ></Image>
              )}
              <Text style={{ fontWeight: "bold", fontSize: 15, marginLeft: 5 }}>
                {item.username}
              </Text>
            </View>

            <View style={styles.cardbody}>
              {item.filename ? (
                <Image
                  style={styles.cardbodyimage}
                  resizeMode="stretch"
                  source={{ uri: url + "filename/" + item.filename }}
                ></Image>
              ) : (
                <View></View>
              )}
            </View>
            <View style={styles.cardfooter}>
              <MaterialCommunityIcons
                onPress={handleLikeClick}
                name={likebutton}
                size={28}
                color={likebuttoncolor}
                style={{ marginLeft: 10, marginTop: 4 }}
              >
                {" "}
              </MaterialCommunityIcons>
              <Text style={{ fontSize: 18, marginLeft: 1 }}>{postlikes}</Text>
              <EvilIcons
                name="comment"
                size={30}
                style={{ marginLeft: 20, marginTop: 4 }}
                color="black"
              />
              <Image
                style={{ marginLeft: 20, marginTop: 4 }}
                source={require("../../assets/share.png")}
              ></Image>
            </View>
            {checkcaption(item.caption)}

            <View style={styles.showcomment}>
              <Text>
                View all {item.comments ? item.comments.length : 0} comments
              </Text>
            </View>

            <View style={styles.comment}>
              <View>
                {user.profileimage ? (
                  <Image
                    source={{ uri: url + "filename/" + user.profileimage }}
                    style={{
                      height: 35,
                      width: 35,
                      borderRadius: 100,
                      marginLeft: 14,
                    }}
                  ></Image>
                ) : (
                  <View></View>
                )}
              </View>

              <View style={styles.addcomment}>
                <Text
                  style={{
                    marginHorizontal: 5,
                    fontSize: 14,
                    color: "#9CA3AF",
                    width: 240,
                  }}
                >
                  Add Comment
                </Text>
              </View>
            </View>
          </View>
        </View>
      </SafeAreaView>
    </>
  );
};

export default Handlenewspost;

const styles = StyleSheet.create({
  showcomment: { marginLeft: 20, marginBottom: 5 },
  addcomment: {
    overflow: "hidden",
    marginLeft: 20,
    marginRight: 20,

    padding: 7,
    backgroundColor: "#E6E7E9",
    borderRadius: 25,
  },
  comment: {
    marginTop: 10,
    flexDirection: "row",
    alignItems: "center",
  },
  email: {
    flexDirection: "row",
    overflow: "hidden",
    marginLeft: 20,
    marginRight: 20,
    marginTop: 10,
    marginBottom: 20,
    padding: 7,
    backgroundColor: "#E6E7E9",
    borderRadius: 25,
  },

  iconout: { width: "20%", alignItems: "center" },
  icon: { height: 35, width: 35, resizeMode: "stretch" },
  icons: {
    flexDirection: "row",
    flexWrap: "wrap",

    marginTop: 1,
    marginHorizontal: 28,
    marginBottom: 20,
  },
  profileimage: {
    width: "12%",
    height: "170%",
    borderRadius: 100,
    resizeMode: "stretch",
  },
  safe: {
    flex: 1,
    marginTop: -10,
  },
  root: {
    flex: 1,
    padding: 16,
  },
  textStyle: {
    fontSize: 14,
  },

  container: {
    justifyContent: "center",
    flex: 1,
  },
  cardfooter: {
    flexDirection: "row",
    alignItems: "center",
  },
  cardbodyimage: {
    height: 350,
    width: "100%",
    marginTop: 3,
    borderRadius: 3,
  },

  cardbody: {},
  cardheader: {
    flexDirection: "row",
    alignItems: "center",
    marginVertical: 12,
  },
  card: {
    marginVertical: 10,
    marginHorizontal: 4,
  },
});

内容的提问来源于stack exchange,提问作者shrijay kesarwani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 12:15:04