Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bug] tauri v2.0.x 'unlisten' work strangely #8916

Closed
canxin121 opened this issue Feb 20, 2024 · 4 comments · Fixed by #8930 or canxin121/tauri#2
Closed

[bug] tauri v2.0.x 'unlisten' work strangely #8916

canxin121 opened this issue Feb 20, 2024 · 4 comments · Fixed by #8930 or canxin121/tauri#2
Labels
status: needs triage This issue needs to triage, applied to new issues type: bug

Comments

@canxin121
Copy link
Contributor

canxin121 commented Feb 20, 2024

Describe the bug

The following js code listens to an event in the useEffect and unlistens the event when the side effect is removed(when refreshing page).
It works fine in v1, and the haddle time will always be 1.
But in v2.x, after refreshing the page, the next listen handleTime will still be increased by 1, and all the triggered event have the same eventId. And when the browser console is open, the behavior is even strangler.

import { invoke } from "@tauri-apps/api/core";
import { useEffect, useState } from "react";
import { listen } from "@tauri-apps/api/event";

export default function App() {
  const [handleTime, setHandleTime] = useState(0);
  function msgHandler(msg) {
    setHandleTime((prev) => prev + 1);
    console.log(msg);
  }
  useEffect(() => {
    let unlistenPromise = listen("event", msgHandler);

    return async () => {
      const unlisten = await unlistenPromise;
      if (unlisten) {
        unlisten()
          .then((rst) => {
            console.log("call unlisten");
          })
          .catch((e) => {
            alert("call unlisten error: " + e);
          });
      }
    };
  }, []);

  return (
    <>
      {/* This button invoke app.emit("event","msg") */}
      <button
        onClick={() => {
          setHandleTime(0);
          invoke("emit", "msg");
        }}
      >
        emit
      </button>
      <h1>handleTime: {handleTime}</h1>
    </>
  );
}

Below are the backend code.

// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use tauri::{generate_handler, Manager, Runtime};

#[tauri::command]
async fn emit<R: Runtime>(
    app: tauri::AppHandle<R>,
    _window: tauri::Window<R>,
) -> Result<(), String> {
    app.emit_all("event", "msg").unwrap();
    Ok(())
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
fn main() {
    tauri::Builder::default()
        .invoke_handler(generate_handler![emit])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

v1 works fine:

v1.mp4

v2 :

V2.mp4
v2_with_console.mp4
{2419A211-AF87-48de-BE07-A13563F09179}

Reproduction

https://github.com/canxin121/test_listen_v1 -> works fine
https://github.com/canxin121/test_listen_v2 -> works strangly

Expected behavior

The behavior of the v2.x version should be consistent with v1

Full tauri info output

for v1:

[✔] Environment
    - OS: Windows 10.0.19044 X64
    ✔ WebView2: 117.0.2045.43
    ✔ MSVC:
        - Visual Studio Build Tools 2019
        - Visual Studio Community 2022
    ✔ rustc: 1.76.0-nightly (e9013ac0e 2023-12-05)
    ✔ cargo: 1.76.0-nightly (623b78849 2023-12-02)
    ✔ rustup: 1.26.0 (5af9b9484 2023-04-05)
    ✔ Rust toolchain: nightly-x86_64-pc-windows-msvc (default)
    - node: 21.2.0
    - pnpm: 8.15.2
    - yarn: 1.22.21
    - npm: 10.2.3

[-] Packages
    - tauri [RUST]: 1.6.0
    - tauri-build [RUST]: 1.5.1
    - wry [RUST]: 0.24.7
    - tao [RUST]: 0.16.7
    - tauri-cli [RUST]: 2.0.0-beta.1
    - @tauri-apps/api [NPM]: 1.5.3
    - @tauri-apps/cli [NPM]: 1.5.10

[-] App
    - build-type: bundle
    - CSP: unset
    - distDir: ../dist
    - devPath: http://localhost:1420/
    - framework: React
    - bundler: Vite

for v2:

[✔] Environment
    - OS: Windows 10.0.19044 X64
    ✔ WebView2: 117.0.2045.43
    ✔ MSVC:
        - Visual Studio Build Tools 2019
        - Visual Studio Community 2022
    ✔ rustc: 1.76.0-nightly (e9013ac0e 2023-12-05)
    ✔ cargo: 1.76.0-nightly (623b78849 2023-12-02)
    ✔ rustup: 1.26.0 (5af9b9484 2023-04-05)
    ✔ Rust toolchain: nightly-x86_64-pc-windows-msvc (environment override by RUSTUP_TOOLCHAIN)
    - node: 21.2.0
    - pnpm: 8.15.2
    - yarn: 1.22.21
    - npm: 10.2.3

[-] Packages
    - tauri [RUST]: 2.0.0-beta.3      
    - tauri-build [RUST]: 2.0.0-beta.2
    - wry [RUST]: 0.36.0
    - tao [RUST]: 0.25.0
    - tauri-cli [RUST]: 2.0.0-beta.1  
    - @tauri-apps/api [NPM]: 2.0.0-beta.1
    - @tauri-apps/cli [NPM]: 2.0.0-beta.1

[-] App
    - build-type: bundle
    - CSP: unset
    - frontendDist: ../dist
    - devUrl: http://localhost:1420/
    - framework: React
    - bundler: Vite

Stack trace

In v2.x, with browser console open, got following trace.

chunk-Y2F7D3TJ.js?v=42918a2b:3 Download the React DevTools for a better development experience: https://reactjs.org/link/react-devtools
VM56:1  Uncaught (in promise) SyntaxError: Unexpected end of JSON input
    at <anonymous>:87:33
(anonymous) @ VM36:87
Promise.then(异步)
value @ VM36:94
(anonymous) @ VM38:130
action @ VM38:269
(anonymous) @ VM38:278
value @ VM38:252
invoke @ core.js:87
listen @ event.js:70
(anonymous) @ App.jsx:12
commitHookEffectListMount @ react-dom.development.js:23150
commitPassiveMountOnFiber @ react-dom.development.js:24926
commitPassiveMountEffects_complete @ react-dom.development.js:24891
commitPassiveMountEffects_begin @ react-dom.development.js:24878
commitPassiveMountEffects @ react-dom.development.js:24866
flushPassiveEffectsImpl @ react-dom.development.js:27039
flushPassiveEffects @ react-dom.development.js:26984
(anonymous) @ react-dom.development.js:26769
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
Show 13 more frames
显示简略信息
VM57:1  Uncaught (in promise) SyntaxError: Unexpected end of JSON input
    at <anonymous>:87:33
(anonymous) @ VM36:87
Promise.then(异步)
value @ VM36:94
(anonymous) @ VM38:130
action @ VM38:269
(anonymous) @ VM38:278
value @ VM38:252
invoke @ core.js:87
listen @ event.js:70
(anonymous) @ App.jsx:12
commitHookEffectListMount @ react-dom.development.js:23150
invokePassiveEffectMountInDEV @ react-dom.development.js:25154
invokeEffectsInDev @ react-dom.development.js:27351
commitDoubleInvokeEffectsInDEV @ react-dom.development.js:27330
flushPassiveEffectsImpl @ react-dom.development.js:27056
flushPassiveEffects @ react-dom.development.js:26984
(anonymous) @ react-dom.development.js:26769
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
Show 12 more frames
显示简略信息
@canxin121 canxin121 added status: needs triage This issue needs to triage, applied to new issues type: bug labels Feb 20, 2024
@canxin121
Copy link
Contributor Author

canxin121 commented Feb 20, 2024

I've located the bug, I'll try to upload a pr to fix it.

@canxin121
Copy link
Contributor Author

canxin121 commented Feb 20, 2024

#8621

In this pr js_event_listeners are stored in the backend Listeners, while in v1 js_event_listeners are stored in the frontend.
In v1, when manually refreshing a page, all js_event_listeners on the frontend are lost to the refresh. In v2, since js_event_listeners are stored on the backend, and useEffect doesn't run the cleanup side-effects function (which sends an unlisten request to the backend) before the page is refreshed, the listener doesn't get cleaned up.

@Gofive
Copy link

Gofive commented Feb 22, 2024

#8621

In this pr js_event_listeners are stored in the backend Listeners, while in v1 js_event_listeners are stored in the frontend. In v1, when manually refreshing a page, all js_event_listeners on the frontend are lost to the refresh. In v2, since js_event_listeners are stored on the backend, and useEffect doesn't run the cleanup side-effects function (which sends an unlisten request to the backend) before the page is refreshed, the listener doesn't get cleaned up.

this bug will be fixed in next release beta verison?

@canxin121
Copy link
Contributor Author

#8621
In this pr js_event_listeners are stored in the backend Listeners, while in v1 js_event_listeners are stored in the frontend. In v1, when manually refreshing a page, all js_event_listeners on the frontend are lost to the refresh. In v2, since js_event_listeners are stored on the backend, and useEffect doesn't run the cleanup side-effects function (which sends an unlisten request to the backend) before the page is refreshed, the listener doesn't get cleaned up.

this bug will be fixed in next release beta verison?

It's not up to me, but I did fix the bug in pr. If you want to use the fixed tauri now, you can either switch the tauri source to my forked git link in cargo.toml, or pull it locally.

这并不由我决定,但是我已经在pr中确实的解决了这个bug. 如果现在就想使用修复后的tauri, 你可以在cargo.toml中将tauri来源切换到我的fork的git链接, 或者pull 到本地使用.

canxin121 added a commit to canxin121/tauri that referenced this issue Feb 23, 2024
Signed-off-by: canxin <1969730106@qq.com>
canxin121 added a commit to canxin121/tauri that referenced this issue Feb 23, 2024
canxin121 added a commit to canxin121/tauri that referenced this issue Feb 27, 2024
@canxin121 canxin121 reopened this Feb 27, 2024
canxin121 added a commit to canxin121/tauri that referenced this issue Feb 28, 2024
amrbashir pushed a commit that referenced this issue Feb 28, 2024
* fix clear residual listeners #8916

* Comment out `println` on successful removal of `js_listeners`

* follow review changes.

* remvoe uneeded result

* Update fix-clear-residual-listeners.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: needs triage This issue needs to triage, applied to new issues type: bug
Projects
None yet
2 participants