当内容脚本注入 React 时告诉后台脚本



>我正在将 React 组件作为脚本注入网页,但这是在通过后台脚本打开的页面上。

我正在尝试做的是等到页面加载并挂载 React 组件,然后向该组件发送消息。不幸的是,我无法让它工作,所以我怀疑这是因为 Chrome 说页面已加载但 React 组件尚未挂载。

在我的后台脚本中,我有以下内容:

function relist(request) {
    const url = 'domain.com';
    chrome.tabs.create({ url },() => {
        chrome.tabs.onUpdated.addListener(reListener);
    });
    // Listen for new relist tab and remove listener when loaded
    function reListener(tabId, info, tab) {
        if(tab.url === url && tab.status === "complete") {
            console.log("Found tab");
            chrome.tabs.sendMessage(tab.id, {action: "relist", data: request.data});
            chrome.tabs.onUpdated.removeListener(reListener);
        }
    }
}

然后在组件中,我注入了以下内容:

componentDidMount() {
    console.log("Mounted Design Upload");
    chrome.runtime.onMessage.addListener(
        (request) => {
            console.log("Received Message");
            if(request.action === "relist") {
                console.log("relist", request);
                this.props.dispatch(currentDesign({
                    id: request.data.design_slug,
                    meta:request.data.meta,
                }));
                this.setState({
                    value: {
                        key: request.data.design_slug,
                        name: request.data.design.title
                    },
                    selectedFile: request.data.file_slug
                })
            }
        });
}

有谁知道我如何告诉后台脚本在发送数据之前等待来自组件的消息?

在内容和后台脚本之间建立长期连接。

想象一个这样的文件夹结构:

├── content
├───── AwesomeComponent.js
├── background
├───── index.js
├── messenger.js
├── manifest.json

您将拥有一个脚本,用于发送/接收来自内容和后台脚本的消息。

messenger.js

import { relist } from 'background/index'
chrome.runtime.onConnect.addListener(function (port) {
  port.onMessage.addListener(function (request) {
    if (request.action === 'mounted') {
       // this message was sent by your AwesomeComponent
       // call relist to send data to content script
       relist()
    }
    if (request.action === 'relist') {
       // this message was sent by your background script
       // dispatch an action with request.data using your state management library
       // this will trigger an re-render in your React app and update its props
    }
  })
})
const context = typeof chrome.runtime.getBackgroundPage !== 'function' ? 'content' : 'background'
export function postMessage (request) {
  if (context === 'content') {
    const port = browser.runtime.connect()
    port.postMessage(request)
  } else {
    const port = browser.tabs.connect(request.tabId)
    port.postMessage(request)
  }
}

content/index.js 中包含 messenger.js 模块。这将添加一个chrome.runtime.onConnect侦听器。

content/AwesomeComponent.js

import React from 'react'
import { render } from 'react-dom'
import messenger from '../messenger'
class AwesomeComponent extends React.Component {
  // [...]
  componentDidUpdate(prevProps) {
    /* 
      Component was updated because a dispatch action was fired 
      through a message coming from the background script.
      Compare previous props and then use setState.
      You SHOULD compare them or it'll cause an infinite rendering loop!
      A comparison may be...
    */
    if (this.props.value.key !== prevProps.value.key) {
      this.setState({
        value: {
          key: props.design_slug,
          name: props.design.title
        },
        selectedFile: props.file_slug
      })
    }
  }
  componentDidMount () {
    // send a message to background
    messenger.postMessage({
       action: 'mounted'
    })
  }
  // [...]
}

messenger.js模块也包含在后台脚本index.js中。这也将添加一个chrome.runtime.onConnect侦听器。

background/index.js

import messenger from '../messenger'
export function relist (data) {
  const data = ...
  chrome.tabs.create({ url: 'domain.com' }, () => {
    chrome.tabs.onUpdated.addListener(function reListener(tabId, info, tab) {
      if(tab.url === url && tab.status === 'complete') {
        console.log('Found tab');
        messenger.postMessage({
          tabId: tab.id,
          action: 'relist', 
          data: data
        })
        chrome.tabs.onUpdated.removeListener(reListener);
      }
   }
}
// other background stuff

最新更新