SPFx - SP PnP JS not working on modern pages

When you are working with Spfx you may choose @pnp/sp library as they provides a fluent API to make building your REST queries intuitive and supports 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:


import pnp from "sp-pnp-js";

pnp.sp.web.lists.getByTitle("Task").select("Title", "ID").items.get().then((items: any[]) =>

this.setState({

listItems: items

)};

});


After building my SPFX webpart, when I deployed in classic page, it worked as expected. But when I added the same webpart in 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:


import { WebPartContext } from "@microsoft/sp-webpart-base";

export interface IMyListTrainingMasterProps {

description: string;

context:WebPartContext;

}


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


public render(): void {

const element: React.ReactElement<IMyListTrainingMasterProps >= React.createElement(

MyListTrainingMaster,

{

description: this.properties.description,

context: this.context

}

);


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


let web = new Web(this.props.context.pageContext.web.absoluteUrl);

web.lists.getByTitle("Task").select("Title", "ID").items.get().then((items: any[]) => {

this.setState({

listItems: items

});

}

});