0

I am using react hooks inside a chrome extension, but when I when updating the state, it is fired multiple times, its not happening when I just console log...

// browser.js
chrome.browserAction.onClicked.addListener(tab => {
    chrome.tabs.sendMessage(tab.id, {
        type: "toggle-popup"
    }, null);
});


// content.js
const [popup, setPopup] = useState(false);
    let number = 1
    const togglePopup = () => setPopup(!popup);
    chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
        if (request.type == "toggle-popup") {
            number++
            togglePopup()
            console.log(number)
            console.log(popup)
        }
})

Its giving me these results...

//1st click on tab icon
2
false

//2nd click on tab icon
3
false
2
true

//3rd click
4
false
3
true
2
true
2
false

I just want it to toggle true / false on click to show / hide a div on the page (I don't want to use popup.js). Any idea what I am doing wrong?

Starlight
  • 13
  • 3

1 Answers1

2

Function component's body is the render function, your code adds a listener on every render

// Runs on every render
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { setState(...) });

Therefore you need to use React API to handle those cases and removing the closure issues that you having too.

For this use useEffect and useRef instead of a local variable.

const Content = () => {
  const [popup, setPopup] = useState(false);
  const numberRef = useRef(0);

  useEffect(() => {
    chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
      const togglePopup = () => setPopup((prev) => !prev);
      if (request.type == "toggle-popup") {
        numberRef.current++;
        togglePopup();
      }
    });
  }, []);
};

...
Dennis Vash
  • 50,196
  • 9
  • 100
  • 118
  • Thank you, I think that has done the trick! You cured my headache :) – Starlight Jan 02 '21 at 01:10
  • unrelated note: the way you set state inside the listener in your example is super important because of the subtle change in scope, i.e., passing in `popup` from outside the listener would not work because of it (this tripped me up good for a few hours!) – rob Apr 25 '22 at 07:09
  • Yes, closures is a common GOTCHA when working with event listeners and especially with `useEffect`, for more context see https://stackoverflow.com/questions/59841800/react-useeffect-in-depth-use-of-useeffect/59841947#59841947 – Dennis Vash Apr 25 '22 at 10:10