React Native中其他state更新时如何避免指定useState重置为初始值
问题根因
- 代码存在状态冗余问题:
likebutton、likebuttoncolor、postlikes三个状态完全可以从item和user信息派生得到,不需要单独声明为useState状态,冗余状态没有和item同步更新,就会出现你以为的「重置」问题。 - 直接修改状态对象:代码里
found ? (item.userlike = true) : false属于直接修改useState定义的item状态,不符合React状态不可变的原则,会导致状态更新不可预测。 - 接口请求返回新的
item数据后,没有补充userlike字段就直接setitem,新的item对象没有用户是否点赞的标记,导致后续计算异常。
修复方案
- 移除三个冗余的点赞相关状态,直接在渲染时根据
item动态计算即可 - 遵循状态不可变原则,所有对
item的修改都通过setitem传入新对象实现,不要直接修改原item - 接口请求拿到最新的帖子数据后,先判断当前用户是否点赞,补充
userlike字段后再更新item状态 - 点赞点击逻辑里直接更新
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
相关产品推荐
相关产品推荐

