You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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存在两个关键错误:

  1. 没有用RoomProvider包裹整个导航容器,导致所有需要访问RoomContext的组件无法获取上下文值,useContext(RoomContext)返回undefined,解构addRoomPost时自然报错。
  2. 错误地将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 17:09:53