1

I want to run a local-first app, so node.js is not available. I try to provide a sqljs database via context provider.

I mostly times get the error

enter image description here

TypeError: Cannot read properties of null (reading 'exec')

The code looks as following

SQLiteContext.js

import React, { createContext, useEffect, useState } from "react";
export const SQLiteContext = createContext();

const SQLiteProvider = ({ children }) => {
  const [SQL, setSQL] = useState(null)
  const [sqliteDB, setSqliteDB] = useState(null)

  useEffect(() => {

    initSqlJs({ locateFile: file => `/js/${file}` }).
    then((aSQL)=>{
        setSQL(aSQL)
        setSqliteDB(new aSQL.Database())
    });
   
  }, []);

  return (
    <SQLiteContext.Provider value={{ SQL,setSQL ,sqliteDB,setSqliteDB }}>
      {children}
    </SQLiteContext.Provider>
  )
}

export { SQLiteProvider };

_document.js - static html

import { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'


export default function Document() {
  return (
    <Html>
      <Head />
      <body>
        <Script src='/js/sql-wasm.js' strategy="beforeInteractive" />
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

App.js

import React, { useContext, useEffect } from "react";
import { SQLiteContext } from "../contexts/SQLiteContext";


export default function App() {
    const {SQL,sqliteDB} = useContext(SQLiteContext)

    const res = sqliteDB.exec("SELECT * FROM hello")

    return (
      <>
      test
      {res}
      </>
    )
  }

index.js

import { SQLiteProvider } from "../contexts/SQLiteContext"
import App from "../components/App"


export default function Home() {
  return (
    <div>
      <SQLiteProvider>
        <App />
      </SQLiteProvider>
    </div>
  )
}

The sqljs/initSqlJs works fine.

The Problem seems to be, that if It gets executed, it's not available yet

I tried alrady

  • put all code in one file
  • put the query inside the InitSqlJs(...).then((...)=>{})
  • do the initSqlJs in the static.html with window.db

It seems I need to get the DB Handle before the ContextProvider, but where?

gnerkus
  • 11,357
  • 6
  • 47
  • 71
pg0
  • 54
  • 1
  • 7
  • 1
    Two problems I noticed: 1. Non-serializable values are used with the `useState` hook; and 2. The call to `initSqlJs` returns a promise (async); but, the code treats it like a synchronous call. You might get away with problem #1. But problem #2 requires an update to the code. If you have not found a solution yet, let me know, and I will offer one. – kofeigen Feb 18 '23 at 22:08
  • As mentioned by @kofeigen, you'll need to handle the async call for the wasm file differently. You'll find a pointer in this answer: https://stackoverflow.com/a/56838577/2259144 – gnerkus Jul 23 '23 at 14:44

0 Answers0