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

React Native Context报错:未找到变量queriesString求助

解决React Native Context传递错误及相关问题

首先,我们来逐个排查你遇到的问题:

1. 直接引发错误的根源:App.js中未定义queriesString

在你的App.js里,你在Provider内部写了{console.log(queriesString + " - From App")},但这个queriesString变量并没有在App组件中声明过——你只是在Provider的value里传了这个属性,所以这里直接抛出了ReferenceError。

修正App.js

我们需要把查询字符串的状态管理放在App组件中,同时把状态和更新函数一起传递给Context Provider,这样子组件才能修改这个值:

import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import HomeScreen from "./app/screens/HomeScreen";
import ScannerScreen from "./app/screens/ScannerScreen";
import { queriesContext } from "./app/global/queriesContext";
import { useState } from "react"; // 引入useState

const Stack = createNativeStackNavigator();

export default function App() {
    // 在这里创建状态,管理查询字符串
    const [queriesString, setQueriesString] = useState("123456789");
    
    // 现在可以正常访问queriesString了
    console.log(queriesString + " - From App");

    return (
        <>
            {/* 把状态和更新函数一起传给Context */}
            <queriesContext.Provider value={{ queriesString, setQueriesString }}>
                <NavigationContainer>
                    <Stack.Navigator initialRouteName='Home' screenOptions={{ headerShown: false }}>
                        <Stack.Screen name='Home' component={HomeScreen} />
                        <Stack.Screen name='Scanner' component={ScannerScreen} />
                    </Stack.Navigator>
                </NavigationContainer>
            </queriesContext.Provider>
        </>
    );
}

2. Context使用方式错误

在HomeScreen.js里,你尝试用数组解构const [queriesString, setQueriesString] = useContext(queriesContext);来获取上下文值,但Context传递的是一个对象(包含queriesString和setQueriesString属性),不是数组,所以这种写法是错误的。

修正HomeScreen.js

import { StyleSheet, Text, View, Image, SafeAreaView, Platform, TextInput, Button, TouchableWithoutFeedback, Keyboard } from "react-native";
import { useNavigation } from "@react-navigation/native";
import React, { useContext, useState } from "react";
import ProductScreen from "../global/GetData";
import { queriesContext } from "../global/queriesContext";

export default function HomeScreen() {
    // 解构Context中的值,而不是数组解构
    const { queriesString, setQueriesString } = useContext(queriesContext);
    const [queries, setQueries] = useState(queriesString);
    const navigation = useNavigation();

    const handleSearch = () => {
        setQueriesString(queries);
    };

    // 移除直接调用ProductScreen()的代码,只在JSX中渲染组件
    return (
        <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
            <SafeAreaView style={styles.MainScreen}>
                <ProductScreen />
                {/* TextInput用onChangeText而不是onChange,直接获取输入文本 */}
                <TextInput 
                    style={styles.TextField} 
                    editable={true} 
                    maxLength='30' 
                    numberOfLines='1' 
                    placeholder='Art no.' 
                    keyboardType='numeric' 
                    onChangeText={(text) => setQueries(text)} // 这里改成onChangeText
                    value={queries} // 添加value绑定,让输入框和state同步
                />
                <Button color='red' title='Search' onPress={handleSearch} />
                <View style={styles.BarcodeBox}>
                    <TouchableWithoutFeedback onPress={() => navigation.navigate("Scanner")}>
                        <Image style={styles.BarcodeImage} source={require("../assets/barcode.png")} />
                    </TouchableWithoutFeedback>
                </View>
            </SafeAreaView>
        </TouchableWithoutFeedback>
    );
}

const styles = StyleSheet.create({
    MainScreen: { /* 你的样式 */ },
    TextField: { /* 你的样式 */ },
    BarcodeBox: { /* 你的样式 */ },
    BarcodeImage: { /* 你的样式 */ },
});

3. GetData.js中API请求未响应查询字符串变化

你的useEffect依赖数组是空的,所以只会在组件挂载时调用一次API,当queriesString变化时不会重新请求。另外,你在then里直接写console.log(data),这时候data还没被更新(因为setData是异步的),应该放在另一个useEffect里监听data变化。

修正GetData.js

import { StyleSheet, Text, View, Image, SafeAreaView, TouchableWithoutFeedback, Keyboard } from "react-native";
import React, { useContext, useState, useEffect } from "react";
import { queriesContext } from "./queriesContext";

export default function ProductScreen() { // 这里改成标准的函数声明,避免变量提升问题
    const { queriesString } = useContext(queriesContext);
    const [isLoading, setLoading] = useState(true);
    const [isPromotion, setPromotion] = useState(false);
    const [data, setData] = useState({
        results: [{ hits: [{ name: { no: "" }, description: { no: "" }, potentialPromotionsLabels: {}, code: "", ean: "" }] }] // 初始化一个安全的结构,避免渲染时报错
    });

    console.log(queriesString + " - From GetData");

    useEffect(() => {
        // 当queriesString变化时重新请求API,所以把它加入依赖数组
        setLoading(true); // 请求开始时设置为加载中
        fetch(
            "SERVER.........", // 替换成你的实际API地址
            {
                method: "POST",
                headers: {
                    Accept: "application/json",
                    "Content-Type": "application/json",
                    "x-algolia-agent": "Algolia for JavaScript (4.13.1); Browser; JS Helper (3.10.0)",
                    "x-algolia-application-id": "***********",
                    "x-algolia-api-key": "************************",
                },
                body: JSON.stringify({
                    requests: [
                        {
                            indexName: "prod_products",
                            params: `query=${queriesString}`, // 用模板字符串更清晰
                        },
                    ],
                }),
            }
        )
            .then((response) => response.json()) // 修复拼写错误:respnse → response
            .then((json) => {
                setData(json);
                console.log(json); // 直接打印返回的json,而不是还没更新的data
            })
            .catch((error) => console.error(error))
            .finally(() => setLoading(false));
    }, [queriesString]); // 添加queriesString到依赖数组

    // 监听data变化,可选
    useEffect(() => {
        if (!isLoading) {
            console.log(data);
        }
    }, [data, isLoading]);

    return (
        <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
            <SafeAreaView style={styles.ProductScreen}>
                <View style={styles.LogoBox}>
                    <Image source={require("../assets/Logo.png")} />
                    <Image
                        style={styles.ProductImage}
                        resizeMode='contain'
                        source={
                            isLoading
                                ? require("../assets/fallback_266x266.png")
                                : {
                                        uri: `https://................/${data.results[0].hits[0].picture.product}`, // 模板字符串
                                  }
                        }
                    />
                </View>

                <View>
                    <View>
                        <Text style={styles.Title}> {data.results[0].hits[0].name.no} </Text>
                        <Text style={styles.Desciption}>{data.results[0].hits[0].description.no}</Text>
                        {/* 先判断potentialPromotionsLabels是否存在,避免报错 */}
                        {data.results[0].hits[0].potentialPromotionsLabels?.[5110] && (
                            <Text style={[styles.Text, styles.color]}>{data.results[0].hits[0].potentialPromotionsLabels[5110].text.no}</Text>
                        )}
                        <Text style={styles.Text}> Price: {data.results[0].hits[0].code}</Text>
                        <Text style={styles.Text}> Article No: {data.results[0].hits[0].code}</Text>
                        <Text style={styles.Text}> EAN: {data.results[0].hits[0].ean}</Text>
                    </View>
                </View>
            </SafeAreaView>
        </TouchableWithoutFeedback>
    );
};

const styles = StyleSheet.create({
    color: { /* 你的样式 */ },
    ProductScreen: { /* 你的样式 */ },
    LogoBox: { /* 你的样式 */ },
    ProductImage: { /* 你的样式 */ },
    Title: { /* 你的样式 */ },
    Desciption: { /* 你的样式 */ },
    Text: { /* 你的样式 */ },
});

4. ScannerScreen扫描后更新查询字符串

现在我们可以在ScannerScreen中使用Context,扫描到条码后直接更新查询字符串,然后返回HomeScreen:

修正ScannerScreen.js

import React, { useState, useEffect, useContext } from "react";
import { Text, View, Alert, StyleSheet } from "react-native";
import { BarCodeScanner } from "expo-barcode-scanner";
import { useNavigation } from "@react-navigation/native";
import { queriesContext } from "../global/queriesContext"; // 引入Context

export default function ScannerScreen() {
    const [hasPermission, setHasPermission] = useState(null);
    const [scanned, setScanned] = useState(false);
    const { setQueriesString } = useContext(queriesContext); // 获取更新函数
    const navigation = useNavigation();

    useEffect(() => {
        const getBarCodeScannerPermissions = async () => {
            const { status } = await BarCodeScanner.requestPermissionsAsync();
            setHasPermission(status === "granted");
        };

        getBarCodeScannerPermissions();
    }, []);

    const handleBarCodeScanned = ({ type, data }) => {
        setScanned(true);
        Alert.alert("Strekkode", data, [
            { 
                text: "Yes", 
                onPress: () => {
                    setQueriesString(data); // 更新查询字符串
                    navigation.goBack(); // 返回HomeScreen
                } 
            }, 
            { text: "No", onPress: () => setScanned(false) }
        ]);
    };

    if (hasPermission === null) {
        return <Text>Requesting for camera permission</Text>;
    }
    if (hasPermission === false) {
        return <Text>No access to camera</Text>;
    }
    return (
        <BarCodeScanner onBarCodeScanned={scanned ? undefined : handleBarCodeScanned} style={[StyleSheet.absoluteFill, styles.container]}>
            <View style={styles.layerTop} />
            <View style={styles.layerCenter}>
                <View style={styles.layerLeft} />
                <View style={styles.focused} />
                <View style={styles.layerRight} />
            </View>
            <View style={styles.layerBottom} />
        </BarCodeScanner>
    );
}

const opacity = "rgba(0, 0, 0, .5)";
const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: "column",
    },
    layerTop: {
        flex: 2,
        backgroundColor: opacity,
    },
    layerCenter: {
        flex: 1,
        flexDirection: "row",
    },
    layerLeft: {
        flex: 1,
        backgroundColor: opacity,
    },
    focused: {
        flex: 10,
    },
    layerRight: {
        flex: 1,
        backgroundColor: opacity,
    },
    layerBottom: {
        flex: 2,
        backgroundColor: opacity,
    },
});

总结一下关键的修复点:

  • 在App组件中管理Context的状态,并传递状态和更新函数
  • 修正Context的解构方式,从对象中获取值而不是数组解构
  • 修复TextInput的onChange为onChangeText,确保正确获取输入文本
  • 为GetData的useEffect添加queriesString依赖,实现查询字符串变化时重新请求API
  • 为ScannerScreen添加Context调用,扫描后更新查询字符串并返回主页
  • 为GetData的data初始化安全的结构,避免渲染时出现空指针错误

这样应该就能解决你遇到的ReferenceError,同时让整个应用的状态流转正常工作了。

内容的提问来源于stack exchange,提问作者EXPZ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 17:55:37