jepiqueau / react-sqlite-app-starter

Ionic/React SQLite Application Starter
MIT License
22 stars 14 forks source link

On page refresh the sqlite isn't called from app.tsx anymore #10

Closed stealthAngel closed 2 years ago

stealthAngel commented 2 years ago

I tried to reproduce this error on a clean project in the simplest way I can explain I updated only tab3.tsx with the code above. Nothing more than a query that shows some names on the page.

import React, { useEffect, useState } from 'react';
import { IonContent, IonHeader, IonPage, IonText, IonTitle, IonToolbar } from '@ionic/react';
import ExploreContainer from '../components/ExploreContainer';
import './Tab3.css';
import { SQLiteDBConnection } from '@capacitor-community/sqlite';
import { sqlite } from '../App';

const Tab3: React.FC = () => {
  const [tests, setTests] = useState<any>([]);
  useEffect(() => {
    const initialize = async (): Promise<Boolean> => {
      try {
        let db: SQLiteDBConnection = await sqlite.createConnection("db_issue9");
        await db.open();
        let randomText = (Math.random() + 1).toString(36).substring(7);
        await db.run("INSERT INTO test (name) VALUES (?)", [randomText]);
        let res: any = await db.query("SELECT * FROM test");
        setTests(res.values);
        console.log(`query ${res}`);
        await db.close();
        return true;
      }
      catch (err) {
        console.log(`Error: ${err}`);
        return false;
      }
    }
    initialize();
  }, []);
  return (
    <IonPage>
      <IonHeader>
        <IonToolbar>
          <IonTitle>Tab 3</IonTitle>
        </IonToolbar>
      </IonHeader>
      <IonContent fullscreen>
        <IonHeader collapse="condense">
          <IonToolbar>
            <IonTitle size="large">Tab 3</IonTitle>
          </IonToolbar>
        </IonHeader>
        {/* <ExploreContainer name="Tab 3 page" /> */}
        <div className="container">
          {tests.map((x: any, index: any) =>
            <div key={index}><IonText>
              {index} {x.name}
            </IonText>
            </div>
          )}
        </div>
      </IonContent>
    </IonPage>
  );
};

export default Tab3;

This code only if your first-page load is tab1.tsx. If you refresh the page while you are on tab3.tsx it won't work. I couldn't figure out a way to fix this problem.

https://user-images.githubusercontent.com/23656202/136422163-828c8c44-624d-42c1-bc1f-e6d209eb8cfb.mp4

jepiqueau commented 2 years ago

@stealthAngel Thanks for reporting this. i was able to reproduce once, but i soon as i switch to Galaxy S5 in dev tools it works and now i could not reproduce it anymore even if i delete the project and re-start from scratch. So it is related to something in Chrome set-up see the Troubleshooting chapter added by @gion-andri in https://github.com/capacitor-community/sqlite/blob/master/docs/Web-Usage.md

Troubleshooting
The web-implementation uses IndexedDB to store the data. IndexedDB-support is checked via userAgent. Pay attention not to modify your userAgent (e.g. selecting an iPhone in the Chrome device simulator in your devtools), as this may break the user-agent check and result in an uninitialized DB (causing an error like this:No available storage method found).

if i look at the video you sent the error message is Error: Error: Not implemented on web. means that jeep-sqlite is not found in the DOM by the @capacitor-community/sqlite plugin which is a bit strange but i saw also that it goes to the Tab3 and after to the App which also means that it could come from somewhere else. My problem is i cannot reproduce it anymore since a switch to Galaxy in Chrome

stealthAngel commented 2 years ago

Hey @jepiqueau ,

Thanks for your reply. The error still occurs. You could try using a different browser. e.g internet explorer firefox maxthon etc.

The only thing I did was changing tab3.tsx to the code above.

Then to run the project I did,

npm install
ionic serve

Refreshing the page on localhost:8100/tab3 gives that error.

I ran through the debug in chrome dev tools, the error is probably on await sqlite.initWebStore();

The catch is thrown by let db: SQLiteDBConnection = await sqlite.createConnection("db_issue9");

jepiqueau commented 2 years ago

@stealthAngel One thing i notice is that in Tab3 you forgot to close the connection after the close of the db

                await sqlite.closeConnection("db_issue9"); 

if you add it have you still the issue?

stealthAngel commented 2 years ago

https://github.com/stealthAngel/react-sqlite-app-starter/tree/test3

The issue still occurs. I made a fork branch with the problem.

jepiqueau commented 2 years ago

@stealthAngel Well i test it on Mac with Google and Safari and on Windows 10 Edge, Google, Firefox and i cannot reproduce the error . I clone the app and copy the code from above for the Tab3. So i really do not know what to do more

jepiqueau commented 2 years ago

@stealthAngel make sure after the clone to do

npm install
npm run build
npx cap sync
npm run build  // after adding your code to the Tab3
npx cap copy
npx cap copy web
npm run start
stealthAngel commented 2 years ago

@jepiqueau I did exactly that, still the same problem

image image image image

chrome, Microsoft edge, firefox, maxthon It seems refreshing the page only works on firefox for me.

stealthAngel commented 2 years ago

https://user-images.githubusercontent.com/23656202/136574974-1dd4ff8b-2311-4b6b-b8e0-61908ac4a192.mp4

https://user-images.githubusercontent.com/23656202/136575051-52436fab-e691-4fff-aab4-7f73c3eadf17.mp4

Windows lets me only record one screen at a time. If you want a full video I can make one. I will also try this on another PC. I'm using windows. At least it works on firefox.

jepiqueau commented 2 years ago

@stealthAngel i finally reproduced the error when i

stealthAngel commented 2 years ago

Yes, you got it. It's the page refresh on tab3 that reproduces the error.

jepiqueau commented 2 years ago

@stealthAngel in fact it start refreshing the Tab3 before ending the refresh of the App so when it create the connection in Tab3 the initWebStore in the App is not completed so the jeep-sqlite is not defined

stealthAngel commented 2 years ago

So the load has to be completed first that makes sense. I currently don't know how to do that. Maybe await useEffect app.tsx

jepiqueau commented 2 years ago

@stealthAngel i don't no myself too. In Vue we move this in the main.ts file. Here i tried to move it in the index.ts file but we cannot define useSQLite in the index.ts

stealthAngel commented 2 years ago

it's okay. It's not breaking just an annoyance when testing. If I find the solution I'll make a pr.

jepiqueau commented 2 years ago

@stealthAngel i found the solution in looking for what i made for view

your index.ts as follow

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
import reportWebVitals from './reportWebVitals';
import { defineCustomElements as jeepSqlite, applyPolyfills, JSX as LocalJSX  } from "jeep-sqlite/loader";
import { HTMLAttributes } from 'react';
import { Capacitor } from '@capacitor/core';
import { CapacitorSQLite, SQLiteConnection, SQLiteDBConnection } from '@capacitor-community/sqlite';
type StencilToReact<T> = {
  [P in keyof T]?: T[P] & Omit<HTMLAttributes<Element>, 'className'> & {
    class?: string;
  };
} ;

declare global {
  export namespace JSX {
    interface IntrinsicElements extends StencilToReact<LocalJSX.IntrinsicElements> {
    }
  }
}

applyPolyfills().then(() => {
  jeepSqlite(window);
});

window.addEventListener('DOMContentLoaded', async () => {
  const platform = Capacitor.getPlatform();
  const sqlite: SQLiteConnection = new SQLiteConnection(CapacitorSQLite)
  try {
    if(platform === "web") {
      console.log('in index.ts')
      const jeepEl = document.createElement("jeep-sqlite");
      document.body.appendChild(jeepEl);
      await customElements.whenDefined('jeep-sqlite');
      console.log('in index.ts after customElements')
      await sqlite.initWebStore();
      console.log('after sqlite.initWebStore()');   
    }
    await sqlite.checkConnectionsConsistency();

    let db: SQLiteDBConnection = await sqlite.createConnection("db_issue9", false, "no-encryption", 1);
    console.log(`db ${JSON.stringify(db)}`)
    await db.open();
    console.log(`after db.open`)
    let query = `
    CREATE TABLE IF NOT EXISTS test (
      id INTEGER PRIMARY KEY NOT NULL,
      name TEXT NOT NULL
    );
    `
    console.log(`query ${query}`)

    const res: any = await db.execute(query);
    console.log(`res: ${JSON.stringify(res)}`);
    await db.close();
    console.log(`after db.close`);
    await sqlite.closeConnection("db_issue9");

    ReactDOM.render(
      <React.StrictMode>
        <App /> 

      </React.StrictMode>,
      document.getElementById('root')
    );

    // If you want your app to work offline and load faster, you can change
    // unregister() to register() below. Note this comes with some pitfalls.
    // Learn more about service workers: https://cra.link/PWA
    serviceWorkerRegistration.unregister();

    // If you want to start measuring performance in your app, pass a function
    // to log results (for example: reportWebVitals(console.log))
    // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
    reportWebVitals();
  } catch (err) {
    console.log(`Error: ${err}`);
    throw new Error(`Error: ${err}`)
  }

});

in the App.ts

...
import { useSQLite } from 'react-sqlite-hook/dist';
...
// Singleton SQLite Hook
export let sqlite: any;

const App: React.FC = () => {
  sqlite = useSQLite();
  return (
  <IonApp>
 ...

and in Tab3.ts

import React, { useEffect, useState } from 'react';
import { IonContent, IonHeader, IonPage, IonText, IonTitle, IonToolbar } from '@ionic/react';
import './Tab3.css';
import { SQLiteDBConnection } from 'react-sqlite-hook/dist';
import { sqlite } from '../App';

const Tab3: React.FC = () => {
  const [tests, setTests] = useState<any>([]);
  console.log('in Tab3')
  useEffect(() => {
    const initialize = async (): Promise<Boolean> => {
      console.log('in Tab3 initialize')
      try {
        const jeepEl = document.querySelector("jeep-sqlite")
        console.log(`jeepEl ${jeepEl}`)
        let db: SQLiteDBConnection = await sqlite.createConnection("db_issue9");
        await db.open();
        let randomText = (Math.random() + 1).toString(36).substring(7);
        await db.run("INSERT INTO test (name) VALUES (?)", [randomText]);
        let res: any = await db.query("SELECT * FROM test");
        setTests(res.values);
        console.log(`query ${res}`);
        await db.close();
        await sqlite.closeConnection("db_issue9");
        return true;
      }
      catch (err) {
        console.log(`Error: ${err}`);
        return false;
      }
    }
    initialize();
  }, []);
  return (
    <IonPage>
      <IonHeader>
        <IonToolbar>
          <IonTitle>Tab 3</IonTitle>
        </IonToolbar>
      </IonHeader>
      <IonContent fullscreen>
        <IonHeader collapse="condense">
          <IonToolbar>
            <IonTitle size="large">Tab 3</IonTitle>
          </IonToolbar>
        </IonHeader>
        <div className="container">
          {tests.map((x: any, index: any) =>
            <div key={index}><IonText>
              {index} {x.name}
            </IonText>
            </div>
          )}
        </div>
      </IonContent>
    </IonPage>
  );
};

export default Tab3;

Voilà

stealthAngel commented 2 years ago

Thank you so much. I pulled it from the repository and it worked. I hope it wasn't a lot of work. I'm really thankfull.