SharePoint User Operations Demo Using PnP JS In React Based SPFx Webpart

PnPjs is an awesome library that providers wrappers around SharePoint REST API so that we as the developers don't have to write repetitive code and also don't have to worry about details on how to pass headers, data, etc. It is not only limited to SharePoint but we can also use it to call graph and Office 365 API. As this library comes as an npm package, it can be used for any node js and javascript based projects. You can learn more about PnP JS at this link. There are lots of packages available within this library that can be used selectively.
 
In this article, we will learn different user operations available and how to use them using PnP JS in React-based SPFx solutions. We will see an example of a web part but this can be used in extensions in a similar way.  
 

Create SPFx Solution

  1. md pnpjsoperations    
  2. cd pnpjsoperations    
Run the below commands in sequence. Open a command prompt and create a directory for the SPFx solution and go to that directory.
 
Let us now create our solution:
  1. yo @microsoft/sharepoint    
Select the below options,
 
SharePoint User Operations Demo Using PnP JS In React Based SPFx Webpart
 
We will be using the React framework here so that we can also explore react concepts. Once you select all options in wizard one by one, it will take some time to generate the code structure. And you should see a success message once completed.
 

Install PnP JS Library Package/s

 
Now let's install the PnPJS npm packages. For this sample, we will be using @sp package so we will only install the sp package but you can install others also based on your requirement. Refer to this link to find a detailed list of packages available within the library.
 
Run the below command,
  1. npm install @pnp/sp --save    
SharePoint User Operations Demo Using PnP JS In React Based SPFx Webpart
 
After it is completed, open the same folder in Visual Studio code (you can use any other editor as well).
 

Install JSON Viewer

 
We need this library just for this article's purpose. PnPJs will call SharePoint REST API which will return us JSON, so in order to view this JSON object we will use this React based library which displays JSON object in a nice and readable format. You can read about this package at this link.
  1. npm i react-json-view  
Now let's modify the code to proceed with the demo. If you want to know about how to get started with React in SPFx web part, you can check my webinar on the same at this link.
 

Passing Web part Context to React Component

 
PnP JS needs a Sharepoint site context to work with, therefore we will pass it from our web part file to React components.
 
Open src\webparts\controls\components\ISampleDemoProps.ts
 
Modify the code as below.
  1. import { WebPartContext } from "@microsoft/sp-webpart-base";    
  2.     
  3. export interface ISampleDemoProps {    
  4.   description: string;    
  5.   spcontext:WebPartContext;    
  6. }    
Open src\webparts\controls\ControlsWebPart.ts
 
Modify the render method to pass the context.
  1. public render(): void {    
  2.    const element: React.ReactElement<ISampleDemoProps> = React.createElement(    
  3.      SampleDemo,    
  4.      {    
  5.        description: this.properties.description,    
  6.        spcontext:this.context    
  7.      }    
  8.    );    
  9.    ReactDom.render(element, this.domElement);    
  10.  }    
Please note we have just added line ‘spcontext:this.context’ .
 

Modify React Component

 
Below are the high-level steps that we will do.
  • Import required library; in our case we will be using pnp package and buttons from Office UI Fabric, React, and also Json-view library to display the response from pnpjs methods to display in a readable format. 
  • Create a state interface,  the properties will be used to store JSON response from PNP js methods and will be bound to JSON view control.
  • Constructor to initialize PnP JS context and state.
  • The render method has been modified to add 4 buttons to demonstrate the respective use case.
  • 4 methods which are called based on button selection.
  • Calling PnP JS methods and changing the state variable jsonResponse.
Open src\webparts\controls\components\SampleDemo.tsx
  1. import * as React from 'react';  
  2. import styles from './SampleDemo.module.scss';  
  3. import { ISampleDemoProps } from './ISampleDemoProps';  
  4. import { escape } from '@microsoft/sp-lodash-subset';  
  5.   
  6. //import library  
  7. import {  PrimaryButton, Stack,MessageBar, MessageBarType } from 'office-ui-fabric-react';  
  8. import { TextField, MaskedTextField } from 'office-ui-fabric-react/lib/TextField';  
  9. import { sp } from "@pnp/sp/presets/all";  
  10. import ReactJson from 'react-json-view';  
  11.   
  12. //create state  
  13. export interface ISampleDemoState {  
  14.  jsonResponse:any; //json object to hold response from pnp js methods  
  15.  Title:any; // to hold value entered in textbox  
  16.  responseOf:string; //to hold which button was clicked and show on webpart  
  17. }  
  18.   
  19. var spObj = null;  
  20.   
  21. export default class SampleDemo extends React.Component<ISampleDemoProps, ISampleDemoState> {  
  22.   
  23.   // constructor to intialize state and pnp sp object.  
  24.   constructor(props: ISampleDemoProps,state:ISampleDemoState) {  
  25.     super(props);  
  26.     this.state = {jsonResponse:null,Title:null,responseOf:""};  
  27.     sp.setup({  
  28.       spfxContext: this.props.spcontext  
  29.     });  
  30.     spObj = sp;  
  31.   }  
  32.   
  33.   public render(): React.ReactElement<ISampleDemoProps> {  
  34.     return (  
  35.       <div className={ styles.sampleDemo }>  
  36.         <div className={ styles.container }>  
  37.           <div className={ styles.row }>  
  38.             <div className={ styles.column }>  
  39.               <span className={ styles.title }>Welcome to PnP JS User Operations Demo!</span>  
  40.             </div>  
  41.           </div>  
  42.         </div>  
  43.         <br></br>  
  44.         <TextField value={this.state.Title} label="Enter User ID" onChange={(e)=> this.setTitle(e.target)}/>  
  45.         <br></br>  
  46.         <Stack horizontal tokens={{childrenGap:40}}>    
  47.                 <PrimaryButton text="Get Current User" onClick={()=>this.getCurrentUser()}  />    
  48.                 <PrimaryButton text="Get Current User Groups" onClick={()=>this.getCurrentUserGroups()} />    
  49.              </Stack>    
  50.              <br></br>  
  51.              <Stack horizontal tokens={{childrenGap:40}}>    
  52.                 <PrimaryButton text="Get All Site Users" onClick={()=>this.getAllSiteUser()} />    
  53.                 <PrimaryButton text="Get User by ID" onClick={()=>this.getUserById()} />   
  54.              </Stack>    
  55.             <br></br>  
  56.             <br></br>  
  57.         {this.state.jsonResponse &&  
  58.           <React.Fragment>  
  59.             <div>Respone from: {this.state.responseOf}</div>  
  60.             <br></br>  
  61.             <ReactJson src={this.state.jsonResponse}  collapsed={false} displayDataTypes={false} displayObjectSize={false}/>  
  62.             </React.Fragment>  
  63.         }  
  64.       </div>  
  65.     );  
  66.   }  
  67.   
  68.   // event handler to set users input to state  
  69.   private setTitle(element) {  
  70.     var val = (element as HTMLInputElement).value;  
  71.     this.setState({"Title":val});  
  72.   }  
  73.   
  74.   // method to get current user  
  75.   private async getCurrentUser(){  
  76.     let user = await sp.web.currentUser.get();  
  77.     this.setState({jsonResponse:user,responseOf:"Get Current User"});  
  78.   }  
  79.   
  80.   // method to get current user groups  
  81.   private async getCurrentUserGroups(){  
  82.     let groups = await sp.web.currentUser.groups();  
  83.     this.setState({jsonResponse:groups,responseOf:"Get Current User Groups"});  
  84.     console.log(groups);  
  85.   }  
  86.   
  87.   //method to get all site users  
  88.   private async getAllSiteUser(){  
  89.     let groups = await sp.web.siteUsers();  
  90.     this.setState({jsonResponse:groups,responseOf:"Get All site users"});  
  91.     console.log(groups);  
  92.       
  93.   }  
  94.   
  95.   //method to get user by id  
  96.   private async getUserById (){  
  97.    let user = await  sp.web.getUserById(parseInt(this.state.Title)).get();  
  98.    this.setState({jsonResponse:user,responseOf:"Get User by ID"});  
  99.   }  
  100. }  
For understanding purposes, I have added comments in the above code.
 

Testing the webpart

 
Let us see this web part in action. Run gulp serve
  1. gulp serve   
Open the SharePoint workbench page.
  1. https://msbuild.com/sites/mylab/_layouts/15/workbench.aspx    
Add a target web part, and when the page loads, we will see the below output:
 
SharePoint User Operations Demo Using PnP JS In React Based SPFx Webpart
 
Click on Get Current User
 
SharePoint User Operations Demo Using PnP JS In React Based SPFx Webpart
 
Click on Get Current User Groups
 
SharePoint User Operations Demo Using PnP JS In React Based SPFx Webpart
 
Click on Get All Site Users
 
This method will return all the site users including groups.
 
SharePoint User Operations Demo Using PnP JS In React Based SPFx Webpart
 
Enter User ID (in my case I am adding 13)
 
SharePoint User Operations Demo Using PnP JS In React Based SPFx Webpart
This article demonstrated how we can use some of PNP js methods related to user operations. 
 
I hope this helps, happy coding!!!