0

I am trying to read a react state when the callback of chrome.tabs.onUpdated.addListener is being called, but it seems the state value is undefined, even though it's set previously.

Here is the hook that I have made.

export const useCurrentTab = () => {
    const [currentTab, setCurrentTab] = useState<chrome.tabs.Tab | undefined>(undefined)
    const [activeTabId, setActiveTabId] = useState<number | undefined>(undefined)

    const getActiveTab = async () => {
        const [tab] = await chrome.tabs.query({ active: true, currentWindow: true })
        console.log(`Setting current tab id to ${tab?.id}`)
        setActiveTabId((prevActiveTabId) => tab?.id || prevActiveTabId)
        return tab
    }

    const updateCurrentTab = (
        tabId: number,
        changeInfo: chrome.tabs.TabChangeInfo,
        tab: chrome.tabs.Tab
    ) => {
        console.log("updateCurrentTab", activeTabId, currentTab, tabId);
        if (changeInfo.status === 'complete' && tabId === activeTabId) {
            console.log(`Tab ${tabId} status changed to ${changeInfo.status}`)
            setCurrentTab(tab)
        }
    }

    useEffect(() => {
        getActiveTab().then((tab) => {
            if (tab && tab.status === 'complete') {
                setCurrentTab(tab)
            }
        })

        chrome.tabs.onUpdated.addListener(updateCurrentTab)

        return () => {
            chrome.tabs.onUpdated.removeListener(updateCurrentTab)
        }
    }, [])

    return currentTab
}

the issue is currentTab isn't updated after the page is loaded, I have debugged and pin pointed the issue by adding console logs.

console.log("updateCurrentTab", activeTabId, currentTab, tabId);

when logging, it shows the activeTabId is undefined, so the check for tabId === activeTabId fails here.

here is the console log in order.

current-tab.tsx:15 Setting current tab id to 1494595641
current-tab.tsx:25 updateCurrentTab undefined undefined 1494595641

1 Answer 1

0
 }, [])

You have passed in an empty dependency array. That means that the effects gets set up on the first render, and never again. Since it's set up on the first render, updateCurrentTab closes over the state value that existed during that first render, which is undefined.

To fix this, you will need to let your effect update as the state changes. I assume getActiveTab is still only supposed to be called once, so you'll want to split your code into two effects, so they can have different dependency arrays. Also, i recommend you move the functions inside the effects, unless they're needed by other parts of the component

useEffect(() => {
  const getActiveTab = async () => {
    const [tab] = await chrome.tabs.query({
      active: true,
      currentWindow: true,
    });
    console.log(`Setting current tab id to ${tab?.id}`);
    setActiveTabId((prevActiveTabId) => tab?.id || prevActiveTabId);
    return tab;
  };

  getActiveTab().then((tab) => {
    if (tab && tab.status === "complete") {
      setCurrentTab(tab);
    }
  });
}, []);

useEffect(() => {
  const updateCurrentTab = (
    tabId: number,
    changeInfo: chrome.tabs.TabChangeInfo,
    tab: chrome.tabs.Tab,
  ) => {
    console.log("updateCurrentTab", activeTabId, currentTab, tabId);
    if (changeInfo.status === "complete" && tabId === activeTabId) {
      console.log(`Tab ${tabId} status changed to ${changeInfo.status}`);
      setCurrentTab(tab);
    }
  };

  chrome.tabs.onUpdated.addListener(updateCurrentTab);

  return () => {
    chrome.tabs.onUpdated.removeListener(updateCurrentTab);
  };
}, [activeTabId, currentTab]); // <------- new dependency array
Sign up to request clarification or add additional context in comments.

1 Comment

You are a legend, I have been trying to fix this for hours now, I tried to set activeTabId, but it would cause it to run recursively.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.