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

SPFx React应用报错:Cannot read properties of undefined (reading 'web')

问题:SPFx应用切换页面返回时抛出"Cannot read properties of undefined (reading 'web')"错误

问题描述

首次进入页面时SPFx应用运行正常,但切换到其他页面再返回时,抛出错误:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'web')

问题根源

  1. 全局SP实例未重置:PnPjs配置中的_sp是全局单例,页面切换时WebPart被销毁,原有上下文失效,但单例未被重置,返回的是绑定了失效上下文的SP实例。
  2. 组件内SP实例初始化时机问题:React组件中_sp变量通过空依赖的useEffect初始化,页面返回组件重新挂载时,第二个useEffect(依赖processName和selectedClient)可能先执行,此时_sp尚未完成初始化,导致调用_sp.web时出错。

修复方案

方案1:修改PnPjs配置,确保每次获取有效SP实例

调整pnpjsConfig.ts,允许传入上下文时强制更新实例,同时增加初始化校验:

import { WebPartContext } from "@microsoft/sp-webpart-base";
import { SPFI, SPFx, spfi } from "@pnp/sp";
import { LogLevel, PnPLogging } from "@pnp/logging";

import "@pnp/sp/web"
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
import "@pnp/sp/folders";
import "@pnp/sp/files";
import "@pnp/sp/files/folder";
import "@pnp/sp/batching";
import "@pnp/sp/attachments";

let _sp: SPFI | null = null;

export const getSP = (context?: WebPartContext): SPFI => {
    // 传入上下文时强制初始化/更新实例,确保上下文有效
    if (context != null) {
        _sp = spfi().using(SPFx(context)).using(PnPLogging(LogLevel.Warning));
    }
    // 实例未初始化时抛出明确错误
    if (_sp === null) {
        throw new Error("SP instance not initialized, please provide WebPartContext first");
    }
    return _sp;
}

方案2:在React组件中直接使用有效上下文初始化SP实例

移除组件内延迟初始化逻辑,直接通过props.context获取SP实例,确保每次组件挂载都使用当前有效上下文:

const HelloWorld = (props: IHelloWorldProps) => {
  // 直接通过传入的上下文初始化SP实例
  const _sp = getSP(props.context);

  const [processName, setProcessName] = React.useState<string>('');
  const [clients, setClients] = React.useState<Array<{ Title: string, Id: string }>>([]);
  const [processes, setProcesses] = React.useState<Array<{ Title: string, Id: string }>>([]);
  const [allDocuments, setAllDocuments] = React.useState<Array<IDocumentItem>>([]);
  const [selectedClient, setSelectedClient] = React.useState<number>();

  React.useEffect(() => {
    const urlParams = new URLSearchParams(window.location.search);
    const myParam = urlParams.get('process');
    if (myParam) setProcessName(myParam);
  }, [])

  React.useEffect(() => {
    const fetchClients = async () => {
      const items = await _sp.web.lists.getByTitle("Klienci").items();
      setClients(items);

      const processList = await _sp.web.lists.getByTitle("Procesy").items();
      setProcesses(processList);

      const docs = await _sp.web.lists.getByTitle("Documents").items();
      const files = await _sp.web.getFolderByServerRelativePath("Documents").files();

      const filesTransformed = await Promise.all(files.map(async e => {
        const item = await _sp.web.getFileByServerRelativePath(e.ServerRelativeUrl).getItem<{ Id: number, Title: string }>("Id", "Title");
        return {
          id: item.Id,
          name: e.Name,
          path: `${e.ServerRelativeUrl}`,
        }
      }));

      const documents = docs.map((doc, index) => {
        return {
          id: doc.Id,
          name: filesTransformed.find(e => e.id === doc.Id)?.name || "",
          path: filesTransformed.find(e => e.id === doc.Id)?.path || "",
          clintsIds: doc.KlienciId,
          processesIds: doc.ProcesyId
        }
      });

      const processId = processList.find(p => p.Title === processName)?.Id;
      const filteredDocuments = documents.filter(docu => docu.processesIds.includes(processId) && docu.clintsIds.includes(selectedClient));

      setAllDocuments(filteredDocuments);
    }
    if (processName) {
      fetchClients();
    }
  }, [processName, selectedClient, _sp])

  // 其余组件代码保持不变
}

方案3:WebPart销毁时重置全局SP实例

在WebPart的onDispose方法中重置全局_sp变量,确保下次进入页面时重新初始化:

  1. 先修改pnpjsConfig.ts导出_sp变量:
export let _sp: SPFI | null = null;
  1. 在WebPart类中更新onDispose方法:
protected onDispose(): void {
  ReactDom.unmountComponentAtNode(this.domElement);
  // 重置全局SP实例
  import("../../pnpjsConfig").then(module => {
    module._sp = null;
  });
}

验证

修改完成后重新打包部署SPFx应用,切换页面再返回,确认错误不再出现,数据能正常加载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 18:46:01