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

SPFx React应用刷新/预览时出现TypeError: Cannot read 'web'属性求助

问题:SPFx应用刷新/预览时抛出"Cannot read properties of undefined (reading 'web')"错误

我基于React开发了SPFx应用,首次进入页面时运行正常,但刷新页面或进入预览模式时,会抛出错误:

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


相关代码

package.json

{
  "name": "bms-next-gen-spfx",
  "version": "0.0.1",
  "private": true,
  "engines": {
    "node": ">=18.17.1 <19.0.0"
  },
  "main": "lib/index.js",
  "scripts": {
    "build": "gulp bundle",
    "clean": "gulp clean",
    "test": "gulp test"
  },
  "dependencies": {
    "@fluentui/react": "^8.106.4",
    "@fluentui/react-components": "^9.52.0",
    "@fluentui/react-list-preview": "^0.2.6",
    "@fluentui/react-portal-compat": "^9.0.146",
    "@microsoft/sp-component-base": "1.19.0",
    "@microsoft/sp-core-library": "1.19.0",
    "@microsoft/sp-lodash-subset": "1.19.0",
    "@microsoft/sp-office-ui-fabric-core": "1.19.0",
    "@microsoft/sp-property-pane": "1.19.0",
    "@microsoft/sp-webpart-base": "1.19.0",
    "@pnp/graph": "^4.13.0",
    "@pnp/logging": "^4.13.0",
    "@pnp/sp": "^4.13.0",
    "@pnp/spfx-controls-react": "3.21.0",
    "@pnp/spfx-property-controls": "3.20.0",
    "react": "17.0.1",
    "react-dom": "17.0.1",
    "tslib": "2.3.1"
  },
  "devDependencies": {
    "@microsoft/eslint-config-spfx": "1.20.1",
    "@microsoft/eslint-plugin-spfx": "1.20.1",
    "@microsoft/rush-stack-compiler-4.7": "0.1.0",
    "@microsoft/sp-build-web": "1.20.1",
    "@microsoft/sp-module-interfaces": "1.20.1",
    "@rushstack/eslint-config": "2.5.1",
    "@types/react": "17.0.45",
    "@types/react-dom": "17.0.17",
    "@types/webpack-env": "~1.15.2",
    "ajv": "^6.12.5",
    "eslint": "8.7.0",
    "eslint-plugin-react-hooks": "4.3.0",
    "gulp": "4.0.2",
    "typescript": "4.7.4"
  }
}

PnPJS配置文件

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

import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/fields";
import "@pnp/sp/lists/web";
import "@pnp/sp/items";
import "@pnp/sp/site-users/web";
import "@pnp/sp/presets/all";


let _sp: SPFI;

export const getSP = (context?: WebPartContext): SPFI => {
    if(context != null) {
        _sp = spfi().using(SPFx(context)).using(PnPLogging(LogLevel.Warning))
    }
    return _sp!
}
import * as React from 'react';
import type { INavigationProps } from './INavigationProps';
import { SPFI } from '@pnp/sp';
import { useEffect, useState } from 'react';
import { INavigation } from '../../../interface';
import { getSP } from '../../../pnpjsConfig';
import styles from './Navigation.module.scss';
import { ComboBoxListItemPicker } from '@pnp/spfx-controls-react/lib/ListItemPicker';
import type { ComboboxProps } from "@fluentui/react-components";
import { IReadonlyTheme } from '@microsoft/sp-component-base';
import {
  Combobox,
  Option,
  useId,
  Field
} from "@fluentui/react-components";
//import { Accordion } from "@pnp/spfx-controls-react/lib/Accordion";

const Navigation = (props:INavigationProps) => {

  const LOG_SOURCE = "Navigation Webpart";
  const LIST_NAME = "Activite";
  const _sp:SPFI = getSP(props.context);
 

  const[activiteItems,setActiviteItems] = useState<INavigation[]>([]);
  const [title, setTitle] = useState('');
  const [status, setStatus] = useState('');
  const [ListId, setListId] = useState('');
  const { semanticColors }: IReadonlyTheme= props.themeVariant!;

  const fetchData = async () => {
    if (!_sp) {
      console.error('SP context is undefined');
    }

    
      const list_data= await _sp.web.lists.getByTitle(LIST_NAME).select("Id")();
      setListId(list_data.Id);
      console.log("List Id ", list_data.Id);

      console.log('context',_sp);
      const items = await _sp.web.lists.getByTitle(LIST_NAME).items.select("Id","Title","Livrable/Id","Livrable/Title","Fonction/Id","Fonction/Title","Process/Id","Process/Title").expand("Livrable","Fonction","Process")();
      console.log('Activite items',items);
      setActiviteItems((items).map((item:any) => {
        return {
          Id: item.Id,
          Title: item.Title,
          LivrableId: item.Livrable.Id,
          LivrableTitle: item.Livrable.Title,
          ProcessId: item.Process.Id,
          ProcessTitle: item.Process.Title,
          Fonction:
            item.Fonction.map((f:any) =>
            ({
              Id: f.Id,
              Title: f.Title
            })
            )
        };
      }));
    }

  

  useEffect(() => {
    fetchData();[props]
  });

问题原因及解决方案

1. PnP配置的空值断言风险

当前getSP函数仅在传入context时初始化_sp,但刷新/预览时组件重新渲染可能出现props.context未及时传入的情况,此时_sp仍为undefined,但函数通过_sp!强制断言非空,导致调用_sp.web时触发错误。

修复getSP函数:

export const getSP = (context?: WebPartContext): SPFI => {
    if (context) {
        _sp = spfi().using(SPFx(context)).using(PnPLogging(LogLevel.Warning));
    }
    if (!_sp) {
        throw new Error("SPFI instance not initialized. Ensure context is provided on first call.");
    }
    return _sp;
}

2. useEffect依赖数组语法错误

当前useEffect的依赖数组写在了函数调用内部,属于语法错误,导致useEffect每次渲染都会执行,且可能在_sp未初始化时调用fetchData。

修复useEffect:

useEffect(() => {
  if (_sp) { // 确保_sp初始化后再执行数据请求
    fetchData();
  }
}, [props, _sp]); // 正确设置依赖数组

3. fetchData空值检查不彻底

当前fetchData中仅打印_sp未定义的日志,但仍继续执行后续代码,直接调用_sp.web导致报错。

修复fetchData函数:

const fetchData = async () => {
  if (!_sp) {
    console.error('SP context is undefined');
    return; // 提前返回,避免后续报错
  }
  
  try {
    const list_data= await _sp.web.lists.getByTitle(LIST_NAME).select("Id")();
    setListId(list_data.Id);
    console.log("List Id ", list_data.Id);

    console.log('context',_sp);
    const items = await _sp.web.lists.getByTitle(LIST_NAME).items.select("Id","Title","Livrable/Id","Livrable/Title","Fonction/Id","Fonction/Title","Process/Id","Process/Title").expand("Livrable","Fonction","Process")();
    console.log('Activite items',items);
    setActiviteItems((items).map((item:any) => {
      return {
        Id: item.Id,
        Title: item.Title,
        LivrableId: item.Livrable.Id,
        LivrableTitle: item.Livrable.Title,
        ProcessId: item.Process.Id,
        ProcessTitle: item.Process.Title,
        Fonction:
          item.Fonction.map((f:any) =>
          ({
            Id: f.Id,
            Title: f.Title
          })
          )
      };
    }));
  } catch (error) {
    console.error(`${LOG_SOURCE} - Error fetching data:`, error);
  }
}

4. 确认WebPart正确传递context

检查WebPart的render方法,确保传递给Navigation组件的context正确:

public render(): void {
  const element: React.ReactElement<INavigationProps> = React.createElement(
    Navigation,
    {
      context: this.context,
      themeVariant: this.props.themeVariant
    }
  );
  ReactDom.render(element, this.domElement);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 01:59:52