SPFx - SP PnP JS Not Working On Modern Pages

When you are working with SPFx, you may choose @pnp/sp library as this provides a fluent API to build your intuitive REST queries and support batching and caching. It is very easy to use. You can find the examples here.

I have used the below snippet to get items from the list.

  1. import pnp from "sp-pnp-js";  
  2.   
  3. pnp.sp.web.lists.getByTitle("Task").select("Title""ID").items.get().then((items: any[]) =>          this.setState({  
  4.     listItems: items  
  5.     )};  
  6. });  

After building my SPFx web part, when I deployed in the classic page, it worked as expected. But when I added the same web part to the Modern page, I got the following error.

GET https://mysite.sharepoint.com/SitePages/_api/web 404 (Not Found)The URL contains /SitePages that shouldn't be included.

This issue occurs as the PnP JS API didn’t get the SharePoint context. So, this is how I fixed the issue.

In the props file, add the webpartcontext prop.

  1. import { WebPartContext } from "@microsoft/sp-webpart-base";  
  2. export interface IMyListTrainingMasterProps {  
  3.   description: string;  
  4.   context:WebPartContext;  
  5. }  

In the webpart.ts file, add the newly created prop and initialize this.context to get the SharePoint context.

  1. public render(): void {  
  2.     const element: React.ReactElement<IMyListTrainingMasterProps > = React.createElement(  
  3.       MyListTrainingMaster,  
  4.       {  
  5.         description: this.properties.description,  
  6.         context: this.context  
  7.       }  
  8.     );  

Now, the final step! In your component (.tsx file), get the context of the web from the context prop which we created as below.

  1. let web = new Web(this.props.context.pageContext.web.absoluteUrl);  
  2. web.lists.getByTitle("Task").select("Title""ID").items.get().then((items: any[]) => {        
  3.         this.setState({  
  4.           listItems: items  
  5.         });  
  6.       }  
  7.     });