如何将类组件改写为函数组件且可在Stack Navigation中作为屏幕使用
解决方案
核心问题说明
- 错误1:
React.useState是Hook,仅允许在函数组件顶层作用域调用,你在TermsAndCondition.js的组件外部直接声明导出isAccepted,必然触发Hook调用报错,且这个全局状态无法触发App组件重渲染。 - 错误2:无法直接从子组件导出内部state供父组件使用,你导入的
isAccepted没有实际响应式效果。 - 错误3:判断逻辑写反:用户未同意时应该显示条款页,同意后显示主页,你当前的三元判断逻辑完全相反。
修改步骤
1. 调整App.js代码
把同意状态存在App组件内部,给条款页传递同意回调,修改后代码如下:
import { NavigationContainer } from "@react-navigation/native"; import "react-native-gesture-handler"; import { createStackNavigator } from "@react-navigation/stack"; import React from "react"; import mapScreen1 from "./src/screens/mapScreen1"; import mapListScreen from "./src/screens/mapListScreen"; import Home from "./src/screens/Home"; import TermsAndConditions from "./src/screens/termscond"; const Stack = createStackNavigator(); export default class App extends React.Component { // 存储条款同意状态 state = { isTermsAccepted: false } // 同意条款的回调方法 handleAcceptTerms = () => { this.setState({ isTermsAccepted: true }) // 如需持久化存储(下次打开无需再同意),可在这里调用AsyncStorage写入状态,启动时读取即可 } render() { return ( <NavigationContainer> {!this.state.isTermsAccepted ? ( <Stack.Navigator screenOptions={{headerShown: false}}> <Stack.Screen name="Terms and Conditions" // 给条款页传递回调方法 component={() => <TermsAndConditions onAccept={this.handleAcceptTerms} />} /> </Stack.Navigator> ) : ( <Stack.Navigator> <Stack.Screen name="Home" component={Home} /> <Stack.Screen name="mapListScreen" component={mapListScreen} /> <Stack.Screen name="mapScreen1" component={mapScreen1} /> </Stack.Navigator> )} </NavigationContainer> ); } }
2. 调整TermsAndCondition.js代码
删掉外部错误的useState声明,接收父组件传递的onAccept回调,修改后代码如下:
import React, { Component } from "react"; import { View, Text, ScrollView, TouchableOpacity, StyleSheet } from "react-native"; const isCloseToBottom = ({ layoutMeasurement, contentOffset, contentSize }) => { const paddingToBottom = 20; return ( layoutMeasurement.height + contentOffset.y >= contentSize.height - paddingToBottom ); }; export default class TermsAndConditions extends Component { state = { accepted: false, }; render() { return ( <View style={styles.container}> <Text style={styles.title}>Terms and conditions</Text> <ScrollView style={styles.tcContainer} onScroll={({ nativeEvent }) => { if (isCloseToBottom(nativeEvent)) { this.setState({ accepted: true, }); } }} > <Text style={styles.tcP}> Welcome to our website. Terms And Condition. </Text> </ScrollView> <TouchableOpacity disabled={!this.state.accepted} // 点击时调用父组件传递的同意回调 onPress={this.props.onAccept} style={this.state.accepted ? styles.button : styles.buttonDisabled} > <Text style={styles.buttonLabel}>Accept</Text> </TouchableOpacity> </View> ); } } // 补充基础样式,可根据需求自行修改 const styles = StyleSheet.create({ container: { flex: 1, padding: 20, backgroundColor: '#fff' }, title: { fontSize: 24, fontWeight: 'bold', marginBottom: 20 }, tcContainer: { flex: 1, marginBottom: 20 }, tcP: { fontSize: 16, lineHeight: 24 }, button: { backgroundColor: '#2196F3', padding: 15, borderRadius: 5, alignItems: 'center' }, buttonDisabled: { backgroundColor: '#ccc', padding: 15, borderRadius: 5, alignItems: 'center' }, buttonLabel: { color: '#fff', fontSize: 16, fontWeight: 'bold' } })
内容的提问来源于stack exchange,提问作者Kmaza04
相关产品推荐
相关产品推荐

