React Native 功能组件在 props 更改时不会更新

问题描述 投票:0回答:1
我有一个功能组件 ViewAlarms,它使用使用状态将警报存储在对象数组中,另一个功能组件 AlarmCard 负责渲染保存警报主要信息的卡片。

ViewAlarms 组件处理选择以进入“编辑”模式,用户单击卡以选择将其删除。但是,更改 Alarm.selected 属性似乎不会更新警报卡,除非 AlarmCard 的子级之一被更新,例如切换开关,然后 AlarmCard 显示它已被选择。

ViewAlarms.jsx

function AlarmsViewScreen({ navigation }) { const { theme, setTheme } = useTheme(); styles = { primaryColor: theme, }; const [alarms, setAlarms] = useState([]); const addAlarm = (newAlarm) => { setAlarms([...alarms, newAlarm]); }; const selectAlarm = (alarm) => { alarm.selected = true; setMode("editing"); setAlarms[alarms]; }; const [mode, setMode] = useState("viewing"); const onTapAlarm = (alarm) => { if (mode == "editing") { selectAlarm(alarm); } else { } }; return ( <View style={{ flex: 1, backgroundColor: "#242424" }}> <StatusBar translucent={true} /> <Text style={{ fontSize: 32, paddingTop: 50, alignSelf: "center", color: "#F8E5EE", fontFamily: "bold", }} > Alarms </Text> <Image source={require("../assets/noalarms.png")} style={ alarms.length == 0 ? { alignSelf: "center", marginTop: 150 } : { display: "none" } } /> <ScrollView style={{ flex: 1 }}> {alarms.map((alarm, index) => ( <TouchableOpacity activeOpacity={0.8} onLongPress={() => { selectAlarm(alarm); }} onPress={() => { onTapAlarm(alarm); }} > <AlarmCard mode={mode} alarm={alarm} /> </TouchableOpacity> ))} </ScrollView> <TouchableOpacity style={{ position: "absolute", bottom: 0, alignSelf: "center", margin: 20, }} > <Pressable onPress={() => { addAlarm({ selected: false, alarmName: "Fajr", alarmTime: "5:40", M: "AM", On: true, Days: ["s1", "m"], }); }} > <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }} > <Image source={require("../assets/newalarm.png")} style={{ tintColor: styles.primaryColor, resizeMode: "contain" }} /> <Image source={require("../assets/plus.png")} style={{ position: "absolute" }} /> </View> </Pressable> </TouchableOpacity> </View> ); }
报警卡.jsx

export const AlarmCard = ({ mode, alarm }) => { console.log(alarm); const images = { selected: require("../assets/selected.png"), notselected: require("../assets/notselected.png"), }; const { theme, setTheme } = useTheme(); const [days, setDays] = useState([ { fri: { display: "F", on: false } }, { sat: { display: "S", on: true } }, { sun: { display: "S", on: false } }, { mon: { display: "M", on: false } }, { tue: { display: "T", on: false } }, { wed: { display: "W", on: true } }, { thu: { display: "T", on: false } }, ]); const index_to_day = ["fri", "sat", "sun", "mon", "tue", "wed", "thu"]; const toggleDay = (index) => { const updated = [...days]; updated[index][index_to_day[index]].on = updated[index][index_to_day[index]] .on ? false : true; setDays(updated); }; const [on, setOn] = useState(true); const toggleSwitch = () => { const off = on ? false : true; setOn(off); }; return ( <View> <View style={{ backgroundColor: "#535353", width: "90%", height: 240, margin: "5%", borderRadius: 20, }} > <Text style={{ fontSize: 28, fontFamily: "bold", color: theme, margin: 20, marginBottom: 10, }} > {alarm.alarmName} </Text> <View style={{ flexDirection: "row" }}> <Text style={{ fontSize: 100, fontFamily: "bold", color: "#F8E5EE", marginHorizontal: 15, }} > {alarm.alarmTime} </Text> <Switch trackColor={{ false: "#838383", true: theme }} thumbColor={"#F8E5EE"} onValueChange={toggleSwitch} value={on} style={{ marginLeft: 80, transform: [{ scaleX: 2 }, { scaleY: 2 }], }} /> </View> <View style={ mode == "editing" ? { position: "absolute", right: 0, marginRight: 20, marginTop: 20, } : { display: "none" } } > <Image source={alarm.selected ? images["selected"] : images["notselected"]} tintColor={alarm.selected ? theme : "#F8E5EE"} /> </View> <View style={{ backgroundColor: "#838383", width: "100%", height: "25%", borderBottomLeftRadius: 20, borderBottomRightRadius: 20, position: "absolute", bottom: 0, }} > <View style={{ flex: 1, flexDirection: "row", marginHorizontal: 10 }}> {days.map((day, index) => ( <Pressable onPress={() => { toggleDay(index); }} key={index} style={{ marginHorizontal: 5, marginTop: 13, borderRadius: 5, borderColor: theme, borderWidth: 2, width: 32, height: 32, backgroundColor: day[index_to_day[index]].on ? theme : "transparent", alignItems: "center", }} > <Text style={{ fontFamily: "bold", fontSize: 24, color: "#F8E5EE" }} > {day[index_to_day[index]].display} </Text> </Pressable> ))} </View> </View> </View> </View> ); };
我尝试使用 useEffect 但它不起作用

并且 console.log(alarm) ** 不会被调用,除非 AlarmCard 的某些子项被更新,例如拨动开关

reactjs react-native react-hooks
1个回答
0
投票
如果要设置复杂的状态值,请使用带有回调函数的设置器:

const toggleDay = index => setDays( old => { const updated = [...old] const [ key, val ] = Object.entries( updated[ index ] )[ 0 ] val.on = !val.on updated[ index ] = { [key]:val } return updated } )
    
© www.soinside.com 2019 - 2024. All rights reserved.