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

React Native Expo应用Android Beta版导航至含FlatList页面崩溃

问题:React Native Expo生产环境导航到含日期选择器页面崩溃

我是一名初级开发者,正在开发基于React Native、Expo和函数式组件的应用。导航到包含日期选择器的页面时,应用会崩溃并跳转到app.json设置的默认启动页。该页面日期选择器默认值为当前日期,选择日期后会查询expo-sqlite并将结果展示在FlatList中。本地用Expo Go测试一切正常,但发布到Android商店Beta版本时出现崩溃,且无法查看生产环境日志。

相关代码

import * as SQLite from "expo-sqlite";
import DateTimePicker from "@react-native-community/datetimepicker";


const Realizadas = ({ navigation }) => {
  const [date, setDate] = useState(new Date());
  const [show, setShow] = useState(false);
  const [msj, setMsj] = useState("");
  const [dataMarca, setDataMarca] = useState([]);
  const [placeHolder, setPlaceHolder] = useState("Select a date");

  const db = openDatabase();

  function openDatabase() {
    if (Platform.OS === "web") {
      return {
        transaction: () => {
          return {
            executeSql: () => {},
          };
        },
      };
    }
    const db = SQLite.openDatabase("myDB.db");
    return db;
  }

  useEffect(() => {
    console.log("useEffect");
    db.transaction((tx) => {
      tx.executeSql(
        "create table if not exists user(name text, lastname text, pass text);",
        [],
        (tx, result) => {
          console.log("Created!");
        },
        (tx, error) => {
          console.error("Error creating db", error);
        }
      );

      tx.executeSql(
        "create table if not exists info (id integer primary key not null, date text, type text, state text, latitude text, longitude text);",
        [],
        (tx, result) => {
          
        },
        (tx, error) => {
          console.error("Error: ", error);

        }
      );
    });

    fetchData(date);
  }, []);

  useFocusEffect(
    React.useCallback(() => {
      fetchData(date);
    }, [])
  );

  const cambia = (event, fechaDatePicker) => {
    setShow(false);
    setDate(fechaDatePicker);
    fetchData(fechaDatePicker);
  };

  const showDatepicker = () => {
    setShow(true);
  };
  function fetchData(selectedDate) {
   
    var nuevaFecha;
    if (selectedDate == null || selectedDate == "") {
      var fechaNueva = new Date();
      var fecha = fechaNueva.getDate(); //Current Date
      var month = fechaNueva.getMonth() + 1; //Current Month
      var year = fechaNueva.getFullYear(); //Current Year
      nuevaFecha =
        year +
        "-" +
        (month <= 9 ? "0" + month : month) +
        "-" +
        (fecha <= 9 ? "0" + fecha : fecha);
    } else {
      var fa = selectedDate;
      var anio = fa.getFullYear();
      var mes = fa.getMonth() + 1;
      if (mes < 10) {
        mes = "0" + mes;
      }
      var dia = fa.getDate();
      nuevaFecha = anio + "-" + mes + "-" + dia;
    }

    setPlaceHolder(nuevaFecha);
    //var query = "Select * from marcacion where estado='ENVIADO'";
    var query =
      "Select * from marcacion where fecha like '%" +
      nuevaFecha +
      "%' and estado='ENVIADO';";
    var params = [];
    db.transaction((tx) => {
      tx.executeSql(
        query,
        params,
        (tx, result) => {
          //console.log(result.rows._array);
          if (result.rows._array.length > 0) {
            setDataMarca(result.rows._array);
            console.log(dataMarca, result.rows._array);
            setMsj("");
          } else {
            setDataMarca([]);
            console.log(dataMarca);
            setMsj("No se encontraron resultados");
          }
        },
        function (tx, err) {
          //console.log(err);
          Alert.alert("Error", "No se encuentran resultados");
          setMsj("No se encontraron resultados");
          setDataMarca([]);
          console.log(dataMarca);
  
        }
      );
    });
  }



  const renderItem = useCallback(
    ({ item }) => (
      <CollapsibleView
        arrowStyling={{ size: 0 }}
        style={styles.itemPrincipal}
        title={
          <Text style={{ color: "black", fontSize: 25 }}>{item.tipo}</Text>
        }
      >
        <Text style={styles.item}>Fecha marcación: {item.fecha}</Text>
        <Text style={styles.item}>Estado de envío: {item.estado}</Text>
      </CollapsibleView>
    ),
    []
  );

  return (
    <View style={styles.viewInicio} {...panResponder.panHandlers}>
      <View style={styles.viewTop}>
        <View style={styles.viewRellenoIzquierda}></View>

        <View style={styles.viewTitulo}>
          <Text style={styles.textoTitulo}>REALIZADAS</Text>
        </View>

        <View style={styles.viewDrawer}>
          <TouchableOpacity
            style={styles.drawer}
            onPress={() => navigation.openDrawer()}
          >
            <FontAwesome5 name="bars" size={24} color="#161924" />
          </TouchableOpacity>
        </View>
      </View>

      <View style={styles.viewDatePicker}>
        <TouchableOpacity onPress={showDatepicker}>
          <View style={styles.main}>
            <Text style={styles.vacio1}></Text>
            <View style={styles.vistaCalendario}>
              <Text style={styles.textoCalendario}>{placeHolder}</Text>
            </View>
            <View style={styles.calendario}>
              <Image
                source={require("../assets/calendario.png")}
                style={styles.logo}
              />
            </View>
          </View>
        </TouchableOpacity>
      </View>

      {show && (
        <DateTimePicker
          testID="dateTimePicker"
          format="YYYY-MM-DD"
          minDate="2020-01-01"
          maxDate="2050-12-31"
          mode={"date"}
          display="inline"
          value={date}
          onChange={cambia}
          style={styles.estiloDatePicker}
        />
      )}

      <View style={styles.viewLista}>
        {dataMarca && (
          <FlatList
            data={dataMarca}
            extraData={dataMarca}
            ListEmptyComponent={
              <View style={styles.viewMensaje}>
                <View style={styles.vistaMsj}>
                  <Text style={styles.textoMsj}>{msj}</Text>
                </View>
              </View>
            }
            renderItem={renderItem}
            keyExtractor={(item) => item.fecha}
            refreshing={true}
          />
        )}
      </View>
    </View>
  );
};

export default Realizadas;

解决方案

  • 修复数据库初始化时机:当前const db = openDatabase();在组件顶层执行,会在组件挂载前初始化数据库,生产环境可能因异步或权限问题导致异常。将数据库初始化移到useEffect内部:
// 移除顶层的const db = openDatabase();
useEffect(() => {
  const db = openDatabase(); // 移到这里
  // 后续的db.transaction逻辑...
}, []);
  • 修复useFocusEffect依赖问题:当前回调依赖为空数组,但内部使用了date状态,会导致闭包捕获旧值,添加date到依赖数组:
useFocusEffect(
  React.useCallback(() => {
    fetchData(date);
  }, [date]) // 添加date依赖
);
  • 处理DateTimePicker取消选择的边界情况:用户取消选择时fechaDatePicker可能为null,添加判断避免无效查询:
const cambia = (event, fechaDatePicker) => {
  setShow(false);
  if (fechaDatePicker) { // 确保有选中日期再更新状态和查询
    setDate(fechaDatePicker);
    fetchData(fechaDatePicker);
  }
};
  • 修正表名不一致并避免SQL注入:代码中创建的表是info,但查询的是marcacion,这会引发生产环境查询错误;同时改用参数化查询避免注入风险:
// 创建表时修正表名和字段名
tx.executeSql(
  "create table if not exists marcacion (id integer primary key not null, fecha text, tipo text, estado text, latitude text, longitude text);",
  [],
  // ...回调
);

// fetchData里的查询改用参数化
var query = "Select * from marcacion where fecha like ? and estado='ENVIADO';";
var params = [`%${nuevaFecha}%`]; // 用参数替代字符串拼接
  • 添加错误边界避免应用崩溃:给组件包裹错误边界,捕获渲染异常:
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // 可在此记录错误
  }

  render() {
    if (this.state.hasError) {
      return <Text>页面加载出错,请重试</Text>;
    }
    return this.props.children;
  }
}

// 使用错误边界包裹组件
export default () => (
  <ErrorBoundary>
    <Realizadas />
  </ErrorBoundary>
);
  • 集成生产环境日志收集:用expo-error-recovery捕获错误信息,方便后续排查:
import * as ErrorRecovery from 'expo-error-recovery';

// 在SQL查询错误回调中添加
function (tx, err) {
  ErrorRecovery.setRecoveryProps({ error: err.message, query: query });
  // ...其他逻辑
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 13:27:06