React Native中父组件传递数组给子组件后如何更新并触发重渲染
问题根因
你的代码存在两处核心问题导致新增任务不生效:
- HomeScreen中存储任务数组的
taskList是普通JS变量,没有通过useState托管为响应式状态:你直接调用push修改数组的操作React无法感知,不会触发HomeScreen重渲染,传递给ItemList的listprop永远是初始值。 - ItemList中将传入的
props.list复制到了本地state中:useState的初始值仅在组件首次挂载时生效,后续父组件传递的listprop发生变化时,子组件的本地state不会自动同步,因此视图不会更新。
你之前的勾选、删除功能可以正常生效,是因为这两个操作修改的是ItemList自身的本地state,能直接触发子组件重渲染,没有涉及父子组件的数据同步。
修复方案
推荐采用状态提升的最佳实践:所有任务数据的修改逻辑统一在HomeScreen中维护,ItemList仅作为纯展示组件接收参数、触发回调,不维护独立的本地状态,避免多组件存储同一份数据导致的同步问题。
1. 修改HomeScreen.jsx
将taskList改为响应式状态,新增修改数据的方法传递给子组件:
import React, { useEffect, useState } from 'react' import { SafeAreaView, StyleSheet, StatusBar } from 'react-native' import Task from '../Components/modelItem' import ItemList from '../Components/ItemList' import FloatButton from '../Components/FloatButton' const HomeScreen = ({ navigation, route }) => { // 将taskList改为响应式状态 const [taskList, setTaskList] = useState([ new Task(1, '示例', '示例任务', new Date(), new Date("2021-10-21")), new Task(2, 'RN TODO', '开发待办应用', new Date(), new Date("2021-11-18")), new Task(3, '待办', '完成某项工作', new Date(), new Date("2021-11-25")), ]) console.log(route.params) useEffect(() => { if (route.params?.description) { console.log('useEffect:') console.log(route.params) // 用setTaskList更新状态,生成新数组触发重渲染 setTaskList(prevList => [...prevList, new Task( Date.now(), // 生成唯一ID,不能传null '测试任务', route.params.description, route.params.creationDate, route.params.expireDate )]) } }, [route.params?.description]) // 勾选任务回调 const handleCheckTask = (taskId, isChecked) => { setTaskList(prevList => { const elem = prevList.find(x => x.id === taskId) elem.isDone = isChecked const newList = prevList.filter(x => x.id !== taskId) isChecked ? newList.push(elem) : newList.unshift(elem) return newList }) } // 删除任务回调 const handleDeleteTask = (taskId) => { setTaskList(prevList => prevList.filter(x => x.id !== taskId)) } return ( <SafeAreaView style={styles}> <ItemList list={taskList} onCheckTask={handleCheckTask} onDeleteTask={handleDeleteTask} /> <FloatButton onPress={() => navigation.navigate('AddNewTask')} /> </SafeAreaView> ) } const styles = StyleSheet.create({ flex: 1, marginTop: StatusBar.currentHeight || 0, }) export default HomeScreen
2. 修改ItemList.jsx
删除本地state,直接使用props传入的数据和回调:
import React from 'react' import { FlatList } from 'react-native-gesture-handler' import { Text } from 'react-native' import Item from './Item' const ItemList = (props) => { const itemRender = ({ item }) => { // 复选框处理函数直接调用父组件回调 const checkBoxHandler = (isChecked) => { props.onCheckTask(item.id, isChecked) } // 计算截止时间剩余时长的逻辑保留 const calculateDeadline = () => { var deltaTime = item.expireDate - new Date() var deltaDays = Math.ceil(deltaTime / (1000 * 60 * 60 * 24)) if (!item.isDone) { if (0 < deltaDays && deltaDays <= 7) return <Text>剩余{deltaDays}天到期</Text> else if (deltaDays == 0) return <Text>今日到期!</Text> else if (deltaDays < 0) return <Text style={{ color: 'red' }}>已逾期</Text> } return null } // 删除处理函数直接调用父组件回调 const deleteHandler = () => { props.onDeleteTask(item.id) } return ( <Item title={item.title} desc={item.desc} checkBoxHandler={checkBoxHandler} calculateDeadline={calculateDeadline} deleteHandler={deleteHandler} isDone={item.isDone} /> ) } const onRefresh = () => { // 刷新逻辑可根据需求在父组件实现后通过props调用 } return ( <FlatList data={props.list} renderItem={itemRender} keyExtractor={item => item.id} onRefresh={onRefresh} /> ) } export default ItemList
内容的提问来源于stack exchange,提问作者wneo
相关产品推荐
相关产品推荐

