React Native报错:Cannot read property 'addRoomPost' of undefined 求助
问题:点击Create按钮触发
Cannot read property 'addRoomPost' of undefined错误 在GameScreen页面点击创建按钮跳转至CreateRoom页面后,点击Create按钮时触发错误:Cannot read property 'addRoomPost' of undefined,已排查导入无问题,求问题原因及解决办法。
相关代码
RoomContext.js
import React, { useState } from "react"; const RoomContext = React.createContext(); export const RoomProvider = ({ children }) => { const [roomPosts, setRoomPosts] = useState([]); const addRoomPost = (title, content) => { setRoomPosts([ ...roomPosts, { id: Math.floor(Math.random() * 99999), title: title, content: content, }, ]); }; const removeRoomPost = (updatedRooms) => { setRoomPosts(updatedRooms); }; return ( <RoomContext.Provider value={{ data: roomPosts, addRoomPost, removeRoomPost, }} > {children} </RoomContext.Provider> ); }; export default RoomContext;
GameScreen.js
import React from "react"; import { View, Text, StyleSheet, TouchableOpacity } from "react-native"; import GameDetails from "./Components/GameDetail"; const GameScreen = ({ navigation }) => { return ( <View> <TouchableOpacity onPress={() => { console.log("CS2"); navigation.navigate("Create"); }} > <GameDetails title="CS2" imageSource={require("../assets/cs2.jpg")} /> </TouchableOpacity> <TouchableOpacity onPress={() => { console.log("LOL "); navigation.navigate("Create"); }} > <GameDetails title="LOL" imageSource={require("../assets/lol.jpg")} /> </TouchableOpacity> <TouchableOpacity onPress={() => { console.log("Valorant"); navigation.navigate("Create"); }} > <GameDetails title="Valorant" imageSource={require("../assets/valo.jpeg")} /> </TouchableOpacity> </View> ); }; const styles = StyleSheet.create({ text: { fontSize: 20, }, }); export default GameScreen;
CreateRoom.js
import React, { useContext, useState } from "react"; import { View, Text, TextInput, StyleSheet, Button, TouchableOpacity, } from "react-native"; import RoomContext from "./RoomContext"; export const CreateRoom = ({ navigation }) => { const { addRoomPost } = useContext(RoomContext); const [title, setTitle] = useState(""); const [content, setContent] = useState(""); const handleCreateRoom = () => { console.log("Room created! Navigating to RoomIndexScreen..."); navigation.navigate("Index"); addRoomPost(title, content); }; return ( <View style={styles.container}> <Text style={styles.label}>Oyun İsmi:</Text> <TextInput style={styles.input} value={title} onChangeText={(text) => setTitle(text)} placeholder="Enter Game Name" placeholderTextColor="#87CEEB" /> <Text style={styles.label}>Lig:</Text> <TextInput style={styles.input} value={content} onChangeText={(text) => setContent(text)} placeholder="Enter League" placeholderTextColor="#87CEEB" /> <TouchableOpacity style={styles.lightBlueButton} onPress={handleCreateRoom} > <Text style={styles.buttonText}>Create</Text> </TouchableOpacity> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, padding: 20, backgroundColor: "#F0F8FF", }, input: { fontSize: 18, borderWidth: 1, borderColor: "#A9A9A9", marginBottom: 15, padding: 10, borderRadius: 8, color: "#87CEEB", }, label: { fontSize: 20, marginBottom: 5, color: "#333", }, lightBlueButton: { backgroundColor: "#4682B4", padding: 15, borderRadius: 20, alignItems: "center", }, buttonText: { color: "#fff", fontSize: 18, }, }); export default CreateRoom;
App.js
import { StatusBar } from "expo-status-bar"; import { StyleSheet, Text, View } from "react-native"; import { NavigationContainer } from "@react-navigation/native"; import { createNativeStackNavigator } from "@react-navigation/native-stack"; import HomeScreen from "./Screens/HomeScreen"; import LoginScreen from "./Screens/LoginScreen"; import GameScreen from "./Screens/GameScreen"; import CreateRoom from "./Screens/CreatRoom"; import RoomContext from "./Screens/RoomContext"; import RoomIndexScreen from "./Screens/RoomIndexScreen"; const Stack = createNativeStackNavigator(); export default function App() { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen options={{ headerShown: false }} name="Login" component={LoginScreen} /> <Stack.Screen name="Home" component={HomeScreen} /> <Stack.Screen name="Game" component={GameScreen} /> <Stack.Screen name="Create" component={CreateRoom} /> <Stack.Screen name="Context" component={RoomContext} /> <Stack.Screen name="Index" component={RoomIndexScreen} /> </Stack.Navigator> </NavigationContainer> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center", }, });
RoomIndexScreen.js
import React, { useContext } from "react"; import { View, Text, StyleSheet, FlatList, Button, TouchableOpacity, } from "react-native"; import RoomContext from "./RoomContext"; import { Feather } from "@expo/vector-icons"; import { EvilIcons } from "@expo/vector-icons"; const RoomIndexScreen = ({ navigation }) => { const { data, addRoomPost, removeRoomPost } = useContext(RoomContext); const handleDeleteRoom = (id) => { const updatedRooms = data.filter((room) => room.id !== id); removeRoomPost(updatedRooms); }; const handleRoomPress = (id, title) => { navigation.navigate("Show", { id, title }); }; return ( <View> <FlatList data={data} keyExtractor={(roomPosts) => roomPosts.title} renderItem={({ item }) => { return ( <TouchableOpacity onPress={() => handleRoomPress(item.id, item.title)} > <View style={styles.row}> <Text style={styles.title}> {item.title} - {item.content} </Text> <View style={styles.iconContainer}> <TouchableOpacity onPress={() => handleDeleteRoom(item.id)}> <Feather style={styles.icon} name="trash" size={30} /> </TouchableOpacity> <TouchableOpacity onPress={() => navigation.navigate("Edit", { id: item.id, }) } > <EvilIcons name="pencil" size={40} /> </TouchableOpacity> </View> </View> </TouchableOpacity> ); }} /> </View> ); }; const styles = StyleSheet.create({ row: { flexDirection: "row", justifyContent: "space-between", paddingVertical: 20, paddingHorizontal: 10, borderTopWidth: 1, borderColor: "gray", }, title: { fontSize: 18, }, iconContainer: { flexDirection: "row", }, icon: { fontSize: 30, marginLeft: 30, }, }); export default RoomIndexScreen;
问题原因及解决办法
核心问题:未正确使用RoomProvider包裹应用
你的App.js存在两个关键错误:
- 没有用
RoomProvider包裹整个导航容器,导致所有需要访问RoomContext的组件无法获取上下文值,useContext(RoomContext)返回undefined,解构addRoomPost时自然报错。 - 错误地将
RoomContext作为屏幕组件添加到Stack导航中,这完全不符合Context的使用逻辑。
次要问题:CreateRoom导入拼写错误
App.js中导入CreateRoom时写成了./Screens/CreatRoom,少了一个字母'e',需修正为./Screens/CreateRoom,否则组件无法正确加载。
优化点:状态更新与跳转顺序
handleCreateRoom中先跳转再更新状态,可能导致RoomIndexScreen无法立即看到最新数据,建议先更新状态再跳转。
修正后的代码
修正后的App.js
import { StatusBar } from "expo-status-bar"; import { StyleSheet, Text, View } from "react-native"; import { NavigationContainer } from "@react-navigation/native"; import { createNativeStackNavigator } from "@react-navigation/native-stack"; import HomeScreen from "./Screens/HomeScreen"; import LoginScreen from "./Screens/LoginScreen"; import GameScreen from "./Screens/GameScreen"; import CreateRoom from "./Screens/CreateRoom"; // 修正拼写错误 import { RoomProvider } from "./Screens/RoomContext"; // 导入RoomProvider import RoomIndexScreen from "./Screens/RoomIndexScreen"; const Stack = createNativeStackNavigator(); export default function App() { return ( <RoomProvider> {/* 用RoomProvider包裹整个导航容器 */} <NavigationContainer> <Stack.Navigator> <Stack.Screen options={{ headerShown: false }} name="Login" component={LoginScreen} /> <Stack.Screen name="Home" component={HomeScreen} /> <Stack.Screen name="Game" component={GameScreen} /> <Stack.Screen name="Create" component={CreateRoom} /> <Stack.Screen name="Index" component={RoomIndexScreen} /> {/* 移除错误的Context屏幕 */} </Stack.Navigator> </NavigationContainer> </RoomProvider> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center", }, });
修正后的CreateRoom.js中的handleCreateRoom
const handleCreateRoom = () => { addRoomPost(title, content); // 先更新状态 console.log("Room created! Navigating to RoomIndexScreen..."); navigation.navigate("Index"); // 再跳转 };
内容的提问来源于stack exchange,提问作者MEren
相关产品推荐
相关产品推荐

