React Native三屏切换时报props.screen handler() is not a function如何解决
问题修复说明
报错原因
- props传递不全:你给每个子页面仅传入了1个切换处理函数,但Modal内需要调用3个切换函数,未传入的函数不存在,自然会报
props.screen handler() is not a function错误 - 组件名拼写错误:App.js中初始content赋值用了小写的
<screen1 />,React 组件名必须大写开头,会导致组件渲染异常 - 子组件缺少状态定义:你提供的Screen1代码中直接使用了
modalVisible和setModalVisible,但没有通过useState声明该状态,运行时也会报错 - 状态逻辑冗余:用3个布尔值管理当前激活页面,维护成本高,容易写错判断逻辑
Modal复用方案合理性
多页面复用主题切换Modal的需求是合理的,但你当前每个页面都重写一遍Modal代码的实现方式不合理,重复代码太多,后续修改要同步改3份,建议将Modal抽为独立公共组件,或者直接放在App父组件中全局管理,只需维护1份代码即可。
修复后代码示例
1. 优化后的App.js
import React, { useState } from "react"; import { StyleSheet, View } from "react-native"; import Screen1 from "./screens/CalcScreen"; import Screen2 from "./screens/Screen1"; import Screen3 from "./screens/Screen2"; // 引入抽离的公共Modal import ThemeModal from "./components/ThemeModal"; export default function App() { // 用单个状态管理当前激活的主题页面,可选值:dark/white/pink const [currentTheme, setCurrentTheme] = useState("dark"); // 全局控制Modal显隐,不用每个页面单独维护 const [modalVisible, setModalVisible] = useState(false); // 切换主题的统一处理函数 const changeTheme = (theme) => { setCurrentTheme(theme); // 切换后自动关闭Modal setModalVisible(false); }; // 根据当前主题渲染对应页面 let renderContent; if (currentTheme === "dark") { renderContent = <Screen1 openModal={() => setModalVisible(true)} />; } else if (currentTheme === "white") { renderContent = <Screen2 openModal={() => setModalVisible(true)} />; } else if (currentTheme === "pink") { renderContent = <Screen3 openModal={() => setModalVisible(true)} />; } return ( <View style={styles.container}> {renderContent} {/* 全局挂载主题切换Modal */} <ThemeModal visible={modalVisible} onClose={() => setModalVisible(false)} onChangeTheme={changeTheme} /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#374351", }, });
2. 抽离的公共ThemeModal组件(新建components/ThemeModal.js)
import React from "react"; import { StyleSheet, Text, View, TouchableOpacity, Modal, Pressable, } from "react-native"; // 所有配置通过props传入,完全复用 const ThemeModal = (props) => { return ( <Modal animationType="slide" transparent={true} visible={props.visible} onRequestClose={props.onClose} > <View style={styles.centeredView}> <View style={styles.modalView}> <View style={styles.button}></View> <Text style={styles.modalText}>Themes</Text> <TouchableOpacity style={styles.darkTheme} onPress={() => props.onChangeTheme("dark")} > <Text>Dark</Text> </TouchableOpacity> <TouchableOpacity style={styles.whiteTheme} onPress={() => props.onChangeTheme("white")} > <Text>White</Text> </TouchableOpacity> <TouchableOpacity style={styles.pinkTheme} onPress={() => props.onChangeTheme("pink")} > <Text>Pink</Text> </TouchableOpacity> <Pressable style={[styles.buttonClose]} onPress={props.onClose} > <Text style={styles.textStyle}>X</Text> </Pressable> </View> </View> </Modal> ) } const styles = StyleSheet.create({ centeredView: { marginStart: 15, justifyContent: "center", alignItems: "center", }, modalView: { marginTop: 200, backgroundColor: "rgba(255,255,255,0.5)", borderRadius: 20, padding: 20, alignItems: "center", shadowColor: "#000", shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.5, shadowRadius: 4, elevation: 5, }, button: { borderRadius: 15, padding: 10, elevation: 2, justifyContent: "center", alignItems: "center", marginTop: 20, }, buttonClose: { backgroundColor: "rgba(1,1,1,1)", height: 40, width: 40, borderRadius: 50, elevation: 2, justifyContent: "center", alignItems: "center", marginTop: 20, }, textStyle: { color: "white", textAlign: "center", }, modalText: { marginBottom: 10, textAlign: "center", }, darkTheme: { padding: 10, marginVertical: 5, backgroundColor: "#333", width: 100, alignItems: "center", borderRadius: 8, }, whiteTheme: { padding: 10, marginVertical: 5, backgroundColor: "#fff", width: 100, alignItems: "center", borderRadius: 8, }, pinkTheme: { padding: 10, marginVertical: 5, backgroundColor: "pink", width: 100, alignItems: "center", borderRadius: 8, }, }); export default ThemeModal;
3. 简化后的子页面(以Screen1为例,另外两个页面同理修改)
import React from "react"; import { StyleSheet, View, Pressable, Text, } from "react-native"; const Screen1 = (props) => { return ( <View style={styles.screen}> {/* 打开Modal的按钮,调用父组件传入的openModal方法 */} <Pressable style={[styles.button, styles.buttonOpen]} onPress={props.openModal} > <Text style={styles.openText}>{">"}</Text> </Pressable> {/* 你页面的其他业务内容 */} </View> ) } const styles = StyleSheet.create({ screen: { flex: 1, backgroundColor: "#fafcff", }, button: { borderRadius: 15, padding: 10, elevation: 2, justifyContent: "center", alignItems: "center", marginTop: 20, }, buttonOpen: { backgroundColor: "rgba(1,143,132,0.6)", position: "absolute", marginTop: 45, marginStart: -25, elevation: 2, height: 70, width: 40, }, openText: { fontSize: 25, fontWeight: "bold", color: "white", textAlign: "right", }, }); export default Screen1;
内容的提问来源于stack exchange,提问作者user10078002
相关产品推荐
相关产品推荐

