admin管理员组

文章数量:1410682

I have a backend app that constantly serves events to my React app via Web Sockets. When a specific event is received a new browser tab should be opened. The application will be run by a user in multiple tabs, so I need to open a new tab only once and prevent it from being opened by all running instances.

I've tried using Redux persistent storage, but it doesn't seem to correspond my needs. The best solution that I've found is Shared Workers.

I've tried using Shared Worker in my React app, but I can't set up it properly. It's either being imported incorrectly or Webpack is unable to load it Uncaught SyntaxError: Unexpected token <

When I googled I haven't found any examples of using Shared Worker in React app (with or without CRA) and at this point, I'm not even sure it's possible. I did found some Web Workers examples, but they have totally different configs.

Can anyone please share some specifics of running Shared Worker in React? Or any other ideas that can provide me with similar functionality will be also greatly appreciated.

Edit: Adding lastest code of what I've tried. Disregard the counter logic, consider just the setup:

worker.js

import React from 'react';

export const startCounter = () => {
  window.self.addEventListener("message", event => {
    console.log(event.data, self);
    let initial = event.data;
    setInterval(() => this.postMessage(initial++), 1000);}); 
}

App.js

import React, { Component } from 'react';
import {startCounter} from './worker';

class App extends Component {

  ponentDidMount() {
    const worker = new SharedWorker(startCounter);
    worker.port.start()
    // worker.postMessage(this.state.counter);
    // worker.addEventListener('message', event => this.setState({counter: event.data}));
  }

  render() {
    return (
      <div className="App">
      </div>
    );
  }
}

export default App;

I have a backend app that constantly serves events to my React app via Web Sockets. When a specific event is received a new browser tab should be opened. The application will be run by a user in multiple tabs, so I need to open a new tab only once and prevent it from being opened by all running instances.

I've tried using Redux persistent storage, but it doesn't seem to correspond my needs. The best solution that I've found is Shared Workers.

I've tried using Shared Worker in my React app, but I can't set up it properly. It's either being imported incorrectly or Webpack is unable to load it Uncaught SyntaxError: Unexpected token <

When I googled I haven't found any examples of using Shared Worker in React app (with or without CRA) and at this point, I'm not even sure it's possible. I did found some Web Workers examples, but they have totally different configs.

Can anyone please share some specifics of running Shared Worker in React? Or any other ideas that can provide me with similar functionality will be also greatly appreciated.

Edit: Adding lastest code of what I've tried. Disregard the counter logic, consider just the setup:

worker.js

import React from 'react';

export const startCounter = () => {
  window.self.addEventListener("message", event => {
    console.log(event.data, self);
    let initial = event.data;
    setInterval(() => this.postMessage(initial++), 1000);}); 
}

App.js

import React, { Component } from 'react';
import {startCounter} from './worker';

class App extends Component {

  ponentDidMount() {
    const worker = new SharedWorker(startCounter);
    worker.port.start()
    // worker.postMessage(this.state.counter);
    // worker.addEventListener('message', event => this.setState({counter: event.data}));
  }

  render() {
    return (
      <div className="App">
      </div>
    );
  }
}

export default App;
Share Improve this question edited Aug 31, 2018 at 21:54 Hisagr asked Aug 31, 2018 at 20:44 HisagrHisagr 6216 silver badges13 bronze badges 6
  • Unexpected token < usually means that you set up the path wrong, and the worker gets a 404 html page instead of a script – Bergi Commented Aug 31, 2018 at 20:50
  • There's the issue with Webpack in CRA (github./facebook/create-react-app/issues/3660) Besides that, I'm not sure how worker.js should look like (the one that is passed to SharedWorker() constructor). In all old examples its immediately invoked function (function () {} ()) and I doubt this is the way to go in React. – Hisagr Commented Aug 31, 2018 at 20:58
  • Usually this happens when you do not import React in a file where you try to use jsx. – trixn Commented Aug 31, 2018 at 20:59
  • added some code – Hisagr Commented Aug 31, 2018 at 21:09
  • There is the opening class bracket missing after Component. – trixn Commented Aug 31, 2018 at 21:51
 |  Show 1 more ment

3 Answers 3

Reset to default 2

make a file called WebWorker.js which looks like this:

export default class WebWorker {
    constructor(worker) {
        const code = worker.toString();
        const blob = new Blob(['('+code+')()']);
        return new SharedWorker(URL.createObjectURL(blob));
    }
}

and import it to your main file and do this:

const workers = new WebWorker(worker);
 workers.postMessage(some message);

Clarifying @Birat's answer: The SharedWorker constructor is looking for a URL, but here you're passing it a function:

    const worker = new SharedWorker(startCounter);

Give this a try instead:

    const worker = new SharedWorker(new URL('./worker', import.meta.url));

I migrated from CRA to Vite for my React App and I had to add type: 'module' when instanciating the SharedWorker:

Before:

    new SharedWorker(new URL('./worker.ts', import.meta.url), {
      name: 'Worker Name',
    });

After

    new SharedWorker(new URL('./worker.ts', import.meta.url), {
      type: 'module',
      name: 'Worker Name',
    });

this solved my issue with the worker not being available during development

From Docs: https://v3.vitejs.dev/guide/features.html#web-workers

本文标签: javascriptUsing Shared Worker in ReactStack Overflow