'how to communicate qt with react in tsx?

I know that there is a solution can communicate qt with js, and it work right.

but I want use react in tsx to develop the frontend webpage, and the previous solution failed at this.

the backend code


#./main.py
import os

from PySide6.QtWidgets import QApplication, QGridLayout, QMainWindow, QTextEdit, QWidget
from PySide6.QtCore import QUrl, Slot, QObject
from PySide6.QtWebEngineWidgets import QWebEngineView

class WebFunction(QObject):
    @Slot(result=str)
    def sayHello(self):
        print("hello world!")
        return "hello world!"

class Webview(QMainWindow):
    def __init__(self,url):
        super().__init__()
        self.resize(800,600)
        self.browser = QWebEngineView(self)
        self.inspector = QWebEngineView(self)
        self.inspector.page().setInspectedPage(self.browser.page())
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        lay = QGridLayout(self.central_widget)
        lay.addWidget(self.browser, 0, 0, 1, 1)
        lay.addWidget(self.inspector, 0, 1, 1, 1)
        self.browser.setUrl(QUrl.fromLocalFile(os.path.abspath(url)))

if __name__ == '__main__':
    import sys
    url = "./html/build/index.html"
    app = QApplication(sys.argv)
    w = Webview(url)
    w.show()
    sys.exit(app.exec())

the frontend code

// ./html/src/app.tsx
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { queryByTitle } from '@testing-library/dom';
import QWebChannel  from './qwebchannel/qwebchannel'


function App() {
  document.addEventListener('DOMContentLoaded',event => {
    const getBackend = new Promise((resolve, reject) => {
      console.log(qt)
      new QWebChannel.QWebChannel(qt.webChannelTransport,
        (channel) => resolve(channel.objects.backend));
    })
  })
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
        <button onClick={()=>console.log('hi')}>123</button>
      </header>
    </div>
  );
}

export default App;

I use the follow command to create a react project:

$npm create-react-app html --template typescript

and the command $./html npm run build to build the production file

and I got a error message said that:

PS C:\Users\Administrator\PycharmProjects\self_control_demon\test\webengine\html> npm run build

> [email protected] build C:\Users\Administrator\PycharmProjects\self_control_demon\test\webengine\html
> react-scripts build

Creating an optimized production build...
Failed to compile.

TS2304: Cannot find name 'qt'.
    11 |   document.addEventListener('DOMContentLoaded',event => {
    12 |     const getBackend = new Promise((resolve, reject) => {
  > 13 |       console.log(qt)
       |                   ^^
    14 |       new QWebChannel.QWebChannel(qt.webChannelTransport,
    15 |         (channel) => resolve(channel.objects.backend));
    16 |     })


npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] build: `react-scripts build`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\Administrator\AppData\Roaming\npm-cache\_logs\2021-12-19T08_37_48_870Z-debug.log

which means that the variable qt doesn't exist, and now I'm confused,how to communicate qt with react in tsx?



Solution 1:[1]

The actual problem is that qt was not declared and will be created by v8 at runtime. So just declare it.

declare global {
  interface Window {
    qt: any;
  }
}

This will dismiss the compile error. For the react side code, we could do it like this:

import React, { useEffect } from "react";
import logo from "./logo.svg";
import "./App.css";
import { QWebChannel } from "qwebchannel";
declare global {
  interface Window {
    myObj: any;
    qt: any;
  }
}

window.myObj = window.myObj || {};

function App() {
  useEffect(() => {
    new QWebChannel(window.qt.webChannelTransport, function (channel) {
      window.myObj = channel.objects.myObj;
    });
  }, []);
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 W.Perrin