Skip to content

Unable to access SPFi object after partial page reload #3334

@argofgra

Description

@argofgra

Major Version

4.x

Minor Version Number

4.18.0

Target environment

SharePoint Framework

Additional environment details

Web parts running from app catalog in standard M365 tenant

Expected or Desired Behavior

The desired behavior is to use the SPFi object without reinitializing the context. The operation is usually retrieving items from a list. But it could also be getting info about the web, retrieving data from another site, etc.

Observed Behavior

I get the error Cannot read properties of undefined (reading 'web') when the web part runs again after a partial page reload. In my example I'm getting the web, but it was originally found trying to access sp.web.lists.

Steps to Reproduce

  1. Setup a HelloWorld web part as described below.
  2. Add this to the home page of a communication site
  3. Setup another page in the comms site, with a link in the navigation
  4. Load home page, allow web part to render (works this time)
  5. Use navigation to go to other page
  6. Use navigation to return to the home page
  7. Observe error

Create a HelloWorld web part that initializes a common SPFi object via a centralized helper.

Web part init:

protected onInit(): Promise<void> {
  getSP(this.context);

  return this._getEnvironmentMessage().then(message => {
    this._environmentMessage = message;
  });
}

Centralized SPFi init:

/* eslint-disable no-var */
import { WebPartContext } from "@microsoft/sp-webpart-base";

// import pnp and pnp logging system
import { ISPFXContext, spfi, SPFI, SPFx as spSPFx } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
import "@pnp/sp/batching";

var _sp: SPFI;

export const getSP = (context?: WebPartContext): SPFI => {
  if (_sp === undefined || _sp === null) {
    //You must add the @pnp/logging package to include the PnPLogging behavior it is no longer a peer dependency
    // The LogLevel set's at what level a message will be written to the console
    _sp = spfi().using(spSPFx(context as ISPFXContext));
  }
  return _sp;
};

Rendered component:
(error occurs on line 14)

import * as React from 'react';
import type { IPnPjsWebPartProps } from './IPnPjsWebPartProps';
import { useEffect, useState } from 'react';
import { getSP } from '../../../helpers/pnpjs-config';

const PnPjsWebPart: React.FunctionComponent<IPnPjsWebPartProps> = (props: IPnPjsWebPartProps) => {
    const [message, setMessage] = useState<string>('Initial value, stil loading...');

    useEffect(()=>{
      // eslint-disable-next-line @typescript-eslint/no-floating-promises
      (async ()=>{
        try {
          const sp = getSP();
          const web = await sp.web(); // errors here on partial page reload
          console.log(web);
          setMessage('Got the web without an error! Hurrah!')
        } catch (e) {
          console.error('Error getting web :\'(', e);
          setMessage((e as Error).message);
        }
      })();
    },[])

    return (
      <section>
        <div>{message}</div>
      </section>
    );
}

export default PnPjsWebPart;

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions