React Native基于React Navigation实现类组件间对象传递与列表更新
解决方案
方案1:最小改动实现:通过路由参数回传更新(适合快速跑通流程)
你现在已经在newMedScreen的提交方法里把新的药物对象通过路由参数传回Home页面了,只需要补全参数接收和全局状态更新的逻辑即可:
步骤1:修正App.js中addMed方法的写法
你原来的写法直接修改原state数组,React可能无法触发重新渲染,调整为符合不可变更新原则的写法:
addMed = (med) => { // 用展开运算符生成新数组,确保state更新能触发重渲染 this.setState({ meds: [...this.state.meds, med] }, () => { console.log(this.state.meds) }) }
步骤2:把addMed方法传递给HomeScreen
修改App.js,将路由组件移到App内部,通过初始参数传递全局方法:
class App extends Component{ state = { meds: [] } addMed = (med) => { this.setState({ meds: [...this.state.meds, med] }, () => { console.log(this.state.meds) }) } // 把路由组件放在App内部,可直接访问实例方法 MyStack = () => { return ( <Stack.Navigator screenOptions={{ headerShown: false }}> {/* 把addMed和全局药物列表通过初始参数传给Home */} <Stack.Screen name="Home" component={HomeScreen} initialParams={{ addMed: this.addMed, meds: this.state.meds }} /> <Stack.Screen name="New Medication" component={newMedScreen} /> </Stack.Navigator> ); } render(){ return( <NavigationContainer> <this.MyStack/> </NavigationContainer> ); } }
步骤3:在HomeScreen中监听传回的药物对象并更新全局状态
修改HomeScreen.js,添加生命周期方法监听路由参数变化:
class HomeScreen extends React.Component{ // 组件更新时检测是否有新传回的药物数据 componentDidUpdate(prevProps) { const currentMed = this.props.route.params?.med const prevMed = prevProps.route.params?.med // 仅当药物参数变化时触发更新,避免重复添加 if (currentMed && currentMed !== prevMed) { this.props.route.params.addMed(currentMed) // 清空参数防止重复触发 this.props.route.params.med = undefined } } render(){ const meds = this.props.route.params?.meds || [] return( <View style={styles.container}> <ScrollView style={styles.content}> <Heading message="meds" /> {/* 渲染药物列表 */} {meds.map(item => <Text key={item.id}>{item.med} - 剂量:{item.dose}</Text>)} </ScrollView> <Button title="新增药物" onPress={() => this.props.navigation.navigate('New Medication')} /> </View> )} }
方案2:规范的单一数据源实现:使用React Context(推荐长期使用)
如果希望后续维护更简单,不需要路由来回传参,直接用React Context共享全局状态是最优选择,完全符合你单一数据源的要求:
步骤1:创建全局Context
新建MedContext.js文件:
import React from 'react' const MedContext = React.createContext() export default MedContext
步骤2:在App.js中用Provider包裹路由,提供全局状态和方法
修改App.js:
import MedContext from './MedContext' const Stack = createStackNavigator(); function MyStack() { return ( <Stack.Navigator screenOptions={{ headerShown: false }}> <Stack.Screen name="Home" component={HomeScreen} /> <Stack.Screen name="New Medication" component={newMedScreen} /> </Stack.Navigator> ); } class App extends Component{ state = { meds: [] } addMed = (med) => { this.setState({ meds: [...this.state.meds, med] }) } render(){ return( <NavigationContainer> {/* 所有子孙组件都可以访问Provider里的全局状态和方法 */} <MedContext.Provider value={{ meds: this.state.meds, addMed: this.addMed }}> <MyStack/> </MedContext.Provider> </NavigationContainer> ); } }
步骤3:在NewMedScreen中直接调用全局新增方法
修改NewMed.js的提交逻辑,不需要再通过路由回传参数:
import MedContext from './MedContext' class newMedScreen extends React.Component{ // 声明使用全局Context static contextType = MedContext state = { med: '', dose: '' } onChangeText = (key, value) => { this.setState({ [key]: value }) } submit = () => { if (this.state.med === '' || this.state.dose === ''){ alert('请填写所有字段') return } const med = { med: this.state.med, dose: this.state.dose, id: uuidV4(), } // 直接调用全局方法更新App状态 this.context.addMed(med) this.setState({ med: '', dose: '' }, () => { this.props.navigation.navigate('Home') }) } // 其余渲染逻辑保持原有即可 }
步骤4:在HomeScreen中直接读取全局药物列表渲染
修改HomeScreen.js:
import MedContext from './MedContext' class HomeScreen extends React.Component{ static contextType = MedContext render(){ const { meds } = this.context return( <View style={styles.container}> <ScrollView style={styles.content}> <Heading message="meds" /> {/* 直接遍历全局列表渲染 */} {meds.map(item => ( <Text key={item.id} style={styles.text}> {item.med} - 剂量:{item.dose} </Text> ))} </ScrollView> <Button title="新增药物" onPress={() => this.props.navigation.navigate('New Medication')} /> </View> )} }
注意:你的
newMedScreen组件名首字母需要改成大写NewMedScreen,否则React会识别为普通DOM标签导致报错。
内容的提问来源于stack exchange,提问作者GabeCunningham
相关产品推荐
相关产品推荐

