如何外部修改React Native类组件的state变量并触发重渲染
问题分析
你遇到的核心问题是:那个独立的Edit()函数和XYZ组件的实例完全没有关联——你在Edit()里赋值的editMode = true只是创建了一个全局变量,和XYZ组件state里的editMode半毛钱关系都没有,自然不会触发组件重渲染。要更新组件的状态,必须调用组件实例的setState()方法,而且得让导航栏的按钮能触发这个操作。
解决方案
下面给你两种可行的实现方式,选一种适合你的就行:
方式一:通过导航参数传递状态更新回调
这种方式最直接,把XYZ组件里的状态更新方法传递给导航栏的按钮:
1. 修改xyz.js的XYZ组件
在组件挂载时,把切换编辑模式的方法绑定到导航参数里,同时实现状态更新的方法:
export default class XYZ extends React.Component { constructor(props) { super(props); this.state = { editMode: false, }; // 绑定this,避免回调里this指向错误 this.toggleEditMode = this.toggleEditMode.bind(this); } componentDidMount() { // 把切换方法设置到导航参数中,让导航栏能调用 this.props.navigation.setParams({ toggleEditMode: this.toggleEditMode }); } toggleEditMode() { // 用setState更新状态,这才是触发组件重渲染的正确方式 this.setState(prevState => ({ editMode: !prevState.editMode })); alert('User wants to edit!'); } render() { return ( <View style={styles.container}> {this.state.editMode ? ( <TouchableHighlight onPress={this._onXPressed} underlayColor="white"> <View style={[styles.flowRight, styles.controlButton]}> <Text style={styles.buttonText}>Edit Mode</Text> </View> </TouchableHighlight> ) : ( <TouchableHighlight onPress={this._onYPressed} underlayColor="white"> <View style={[styles.flowRight, styles.controlButton]}> <Text style={styles.buttonText}>Non Edit Mode</Text> </View> </TouchableHighlight> )} </View> ); } } // 删掉那个没用的独立Edit函数 // export function Edit() { ... }
2. 修改abc.js的导航按钮
在navigationOptions里调用导航参数里的toggleEditMode方法:
import XYZ from './xyz'; import { pencilEditButton } from './Images'; const App = createStackNavigator({ Home: { // 这里你之前写的"My App"应该是XYZ组件吧?修正一下 screen: XYZ, navigationOptions: ({ navigation }) => ({ title: 'myApp', headerRight: ( <View> <TouchableHighlight onPress={() => navigation.getParam('toggleEditMode')()} underlayColor="gray" > <View> <Image source={pencilEditButton} style={styles.navigationButtonImage} /> </View> </TouchableHighlight> </View> ), }), }, }); export default createAppContainer(App);
方式二:把编辑状态放到导航栈的state中
如果后续有多个页面需要共享编辑状态,可以把状态提升到导航栈的state里,XYZ组件监听导航参数的变化来更新自身视图:
1. 修改abc.js的导航配置
给导航栈添加初始state,并在按钮点击时更新导航state:
import XYZ from './xyz'; import { pencilEditButton } from './Images'; const App = createStackNavigator({ Home: { screen: XYZ, navigationOptions: ({ navigation }) => ({ title: 'myApp', headerRight: ( <View> <TouchableHighlight onPress={() => { // 更新导航栈的state navigation.setParams({ editMode: !navigation.state.params?.editMode }); alert('User wants to edit!'); }} underlayColor="gray" > <View> <Image source={pencilEditButton} style={styles.navigationButtonImage} /> </View> </TouchableHighlight> </View> ), }), }, }, { // 设置导航栈的初始参数 initialRouteParams: { editMode: false } }); export default createAppContainer(App);
2. 修改xyz.js的XYZ组件
直接使用导航参数里的editMode,或者监听参数变化同步到自身state:
export default class XYZ extends React.Component { constructor(props) { super(props); this.state = { editMode: props.navigation.state.params.editMode, }; } // 监听导航参数变化,更新自身state componentDidUpdate(prevProps) { if (prevProps.navigation.state.params.editMode !== this.props.navigation.state.params.editMode) { this.setState({ editMode: this.props.navigation.state.params.editMode }); } } render() { // 也可以直接用this.props.navigation.state.params.editMode,不用自身state return ( <View style={styles.container}> {this.state.editMode ? ( <TouchableHighlight onPress={this._onXPressed} underlayColor="white"> <View style={[styles.flowRight, styles.controlButton]}> <Text style={styles.buttonText}>Edit Mode</Text> </View> </TouchableHighlight> ) : ( <TouchableHighlight onPress={this._onYPressed} underlayColor="white"> <View style={[styles.flowRight, styles.controlButton]}> <Text style={styles.buttonText}>Non Edit Mode</Text> </View> </TouchableHighlight> )} </View> ); } }
关键知识点提醒
- React组件的状态必须通过
setState()来更新,直接修改this.state不会触发重渲染。 - 导航栏的
navigationOptions是在组件外部定义的,要和页面组件通信,必须通过导航的params机制来传递回调或状态。 - 避免使用全局变量来管理组件状态,这会导致状态混乱,难以维护。
内容的提问来源于stack exchange,提问作者JeffB6688
相关产品推荐
相关产品推荐

