I have a simple app that makes a connection to a sqlite database, reads results from that database, and displays them. Here is the app:
import React, { useEffect, useState } from 'react'; import { View, Text } from 'react-native' import * as SQLite from "expo-sqlite"; import * as FileSystem from 'expo-file-system'; import { Asset } from 'expo-asset'; async function openDatabase() { if (!(await FileSystem.getInfoAsync(FileSystem.documentDirectory + 'SQLite')).exists) { await FileSystem.makeDirectoryAsync(FileSystem.documentDirectory + 'SQLite'); } await FileSystem.downloadAsync( Asset.fromModule(require('./assets/banana-dict.db')).uri, FileSystem.documentDirectory + 'SQLite/banana-dict.db' ); return SQLite.openDatabase('banana-dict.db'); } export default function App() { const [ dicts, setDicts ] = useState([]); const [ db, setDb ] = useState({ transaction: () => { return { executeSql: () => {}, }; }}); const updateDicts = (a) => { setDicts( Object.fromEntries(a.map(({rowid, ...rest}) => [rowid, rest])) ); } const fetchDicts = () => { console.log('fetch') db.transaction((tx) => { tx.executeSql( `select rowid, * from dicts;`, [], (_, { rows: { _array } }) => { console.log(_array); updateDicts(_array); } ); }); } useEffect(() => { openDatabase().then((value) => { setDb(value); fetchDicts(); }); }, []); return ( <View style={{marginTop: 100}}> <Text>Open App.js to start working on your app!</Text> <Text>{JSON.stringify(dicts)}</Text> </View> ); }
banana-dict.db
is a preexisting database I’m using for this app.
I’ve found that if I start the app and open it on my phone, the dicts
state (ie, results of a query on the db) do not appear. However, if I press r
in the console for a refresh, the results appear immediately.
Anyone know why this is?
Advertisement
Answer
When the app starts, the initial db
value is set. The first effect batches setDb
and fetchDicts
, so db.transaction
has not been updated with the value of the setDb
call. Because Expo has stateful refresh, the db
is no longer set as the initial value but has the result of setDb
, so fetchDicts
works, and the results appear.
One way to fix this would be to move fetchDicts
into its own effect, and call it when db
changes.
useEffect(() => { openDatabase().then((value) => { setDb(value); }); }, []); useEffect(() => { fetchDicts(); // will do nothing until db connection is open }, [db]);