You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Chrome扩展:Storage值无法在组件中显示的问题求助

React Chrome扩展问题:右键保存的naviID无法在popup输入框显示

基于Udemy教程开发的React Chrome扩展中,通过右键菜单选项保存到Storage的naviID值,无法在popup组件的对应输入框中显示。以下是相关代码及问题分析:

核心问题原因

存储与读取的结构不匹配:在Storage.ts的set方法中,将数据包裹在values对象下存储,但get方法直接从根对象读取目标字段,导致无法获取到保存的值。

相关代码

Storage.ts

export interface LocalStorage {
  shopURL?: string;
  naviID?: string;
}

export type LocalStorageKeys = keyof LocalStorage;

export function setStoredShopURL(shopURL: string): Promise<void> {
  const values: LocalStorage = {
    shopURL,
  };
  return new Promise((resolve) => {
    chrome.storage.local.set({ values }, () => {
      resolve();
    });
  });
}

export function getStoredShopURL(): Promise<string> {
  const keys: LocalStorageKeys[] = ["shopURL"];
  return new Promise((resolve) => {
    chrome.storage.local.get(keys, (res: LocalStorage) =>
      resolve(res.shopURL ?? "")
    );
  });
}

export function setStoredNaviID(naviID: string): Promise<void> {
  console.log(`naviID inside setStoredNaviID: ${naviID}`);
  const values: LocalStorage = {
    naviID,
  };
  return new Promise((resolve) => {
    chrome.storage.local.set({ values }, () => {
      resolve();
    });
  });
}

export function getStoredNaviID(): Promise<string> {
  const keys: LocalStorageKeys[] = ["naviID"];
  return new Promise((resolve) => {
    chrome.storage.local.get(keys, (res: LocalStorage) =>
      resolve(res.naviID ?? "")
    );
  });
}
import * as React from "react";
import { createRoot } from "react-dom/client";
import IconButton from "@mui/material/IconButton";
import OutlinedInput from "@mui/material/OutlinedInput";
import InputLabel from "@mui/material/InputLabel";
import InputAdornment from "@mui/material/InputAdornment";
import FormControl from "@mui/material/FormControl";
import ClearIcon from "@mui/icons-material/Clear";
import FormHelperText from "@mui/material/FormHelperText";
import Container from "@mui/material/Container";
import Typography from "@mui/material/Typography";
import { useEffect, useState } from "react";
import "./popup.css";
import { getCurrentTab } from "../background/background";
import { correctUserUrlInput } from "../utils/helperFunctions";
import { getStoredNaviID } from "../utils/storage";

function App() {
  const [shopURL, setShopURL] = useState("");
  const [naviID, setNaviID] = useState("");

  const handleClickDeleteUserInput = () => {
    setShopURL("");
  };

  useEffect(() => {
    getCurrentTab().then((tab) => {
      const shortenedURL = correctUserUrlInput(tab.url);
      console.log(shortenedURL);
      setShopURL(shortenedURL);
    });
    getStoredNaviID().then((naviID) => {
      console.log(naviID);
      setNaviID(naviID);
    });
  }, []);

  return (
    <>
      <Typography variant="h4">React URL Picker</Typography>
      <Container maxWidth="xl">
        <FormControl fullWidth variant="outlined" margin="normal">
          <InputLabel htmlFor="outlined-adornment-url">Shop URL</InputLabel>
          <OutlinedInput
            id="outlined-adornment-url"
            type="text"
            value={shopURL}
            onChange={(event) => setShopURL(event.target.value)}
            endAdornment={
              <InputAdornment position="end">
                <IconButton
                  aria-label="delete user input"
                  onClick={handleClickDeleteUserInput}
                  edge="end"
                >
                  <ClearIcon />
                </IconButton>
              </InputAdornment>
            }
            label="url"
          />
          <FormHelperText id="my-helper-text-url">
            Ihr müsst euch auf einer Shopseite befinden, damit diese automatisch
            ausgelesen wird.
          </FormHelperText>
        </FormControl>
        <FormControl fullWidth variant="outlined" margin="normal">
          <InputLabel htmlFor="outlined-naviID">Navi-ID</InputLabel>
          <OutlinedInput
            id="outlined-naviID"
            type="text"
            value={naviID}
            onChange={(event) => setNaviID(event.target.value)}
            label="naviID"
          />
          <FormHelperText id="my-helper-text-naviID">
            Navi-ID der aktuellen Seite
          </FormHelperText>
        </FormControl>
      </Container>
    </>
  );
}

const container = document.createElement("div");
document.body.appendChild(container);
const root = createRoot(container);
root.render(<App />);

background.ts

import { getNaviID } from "../utils/helperFunctions";
import { setStoredNaviID } from "../utils/storage";

export async function getCurrentTab() {
  let queryOptions = { active: true, currentWindow: true };
  let [tab] = await chrome.tabs.query(queryOptions);
  return tab;
}

chrome.runtime.onInstalled.addListener(() => {
  chrome.contextMenus.create({
    title: "NaviID speichern",
    id: "saveNaviId",
  });
});

chrome.contextMenus.onClicked.addListener((clickData) => {
  if (clickData.menuItemId == "saveNaviId") {
    console.log("CLICK!");
    getCurrentTab().then((tab) => {
      console.log(tab.url);
      const naviID = getNaviID(tab.url);
      console.log(naviID);
      setStoredNaviID(naviID[0]);
    });
  }
});

manifest.json

{
  "manifest_version": 3,
  "name": "React URL Picker",
  "description": "React URL Picker for the Shopline Content Team",
  "version": "1.0.0",
  "icons": {
    "16": "cntnt.png",
    "48": "cntnt.png",
    "128": "cntnt.png"
  },
  "action": {
    "default_popup": "popup.html",
    "default_title": "React URL Picker",
    "default_icon": "cntnt.png"
  },
  "options_page": "options.html",
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["contentScript.js"]
    }
  ],
  "permissions": ["storage", "tabs", "activeTab", "contextMenus"]
}

修复方案

有两种可行的修复方式,任选其一即可:

方案1:修改存储逻辑,直接存储字段(推荐)

调整setStoredShopURL和setStoredNaviID方法,去掉values包裹,直接存储目标字段:

export function setStoredShopURL(shopURL: string): Promise<void> {
  return new Promise((resolve) => {
    chrome.storage.local.set({ shopURL }, () => {
      resolve();
    });
  });
}

export function setStoredNaviID(naviID: string): Promise<void> {
  console.log(`naviID inside setStoredNaviID: ${naviID}`);
  return new Promise((resolve) => {
    chrome.storage.local.set({ naviID }, () => {
      resolve();
    });
  });
}

此时原有的get方法可以正常工作,因为存储的键就是shopURL和naviID,与get方法读取的键一致。

方案2:修改读取逻辑,匹配存储结构

调整getStoredShopURL和getStoredNaviID方法,从values对象中读取目标字段:

export function getStoredShopURL(): Promise<string> {
  return new Promise((resolve) => {
    chrome.storage.local.get("values", (res) => {
      resolve(res?.values?.shopURL ?? "");
    });
  });
}

export function getStoredNaviID(): Promise<string> {
  return new Promise((resolve) => {
    chrome.storage.local.get("values", (res) => {
      resolve(res?.values?.naviID ?? "");
    });
  });
}

这种方式不需要修改set方法,只需让读取逻辑匹配存储的嵌套结构。

额外检查点

  1. 确认getNaviID函数返回的数组是否包含有效值,可通过background中的console.log(naviID)输出验证。
  2. 打开Chrome扩展的开发者工具(右键popup选择“检查”),查看getStoredNaviID的console.log(naviID)输出,确认是否为空或未定义。

内容的提问来源于stack exchange,提问作者Stefan Strathmeier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 08:55:54