SPFx – Using PnPClientStorage

Introduction

Hi Friends, in this post we will how we can make use of browser storage features in SPFx using PnPClientStorage.

Why do we need to use browser storage?

You may ask yourself a question that why do I need to use this? what is the advantage of use the browser storage? Is it secured? Let us see the features of browser storage.

Consider you have a scenario of pulling a custom property from UPS and you are using it different web parts on a page. The classical model is to use pull the information from UPS on all the web parts whenever is required or to store the information on a SharePoint list to access it easily. Either way requires a communication to SharePoint. What if there is a way to reduce the communication? the solution is to use the browser storage. You can store the custom property information of the current user in the local storage and then accessing the storage value on all the web parts. You can also schedule a time for the value to refresh.

The browser storage is used mainly for easy access of information that won’t be modified for a long time. Any sensitive data should not be stored using the local storage. The storage should be used with cautious because overloading the browser local storage will have an impact on the page performance.

Why we need to use PnPClientStorage?

The normal local storage method is allowed to store the key-value pair where the value should always be the string. PnPClientStorage module provides a thin wrapper over the browser storage options for both local and session. If neither option is available then it shims storage with a non-persistant in memory polyfill.

Focus on the Code

Let us start by creating a new web part project using yeoman SharePoint generator, before that create a folder where you want to create the web part. Navigate to that folder and run the below command.

yo @microsoft/sharepoint

The generator will asks you couple of questions,

  • Enter the webpart name as your solution name, and then select Enter.
  • Select Create a subfolder with solution name for where to place the files.
  • Select Y to allow the solution to be deployed to all sites immediately.
  • Select N on the question if solution contains unique permissions.
  • Enter the webpart name
  • Enter the webpart description
  • Choose the framework as ‘React

Once the project is created, install the required pnp modules from npm using the below command. I had created a webpart with a name LocalStorage.

npm i @pnp/sp @pnp/common --save-exact

Open the code in VSCode which is my favorite and flexible code editor for SharePoint Framework. You can directly open the project folder from the file menu or use the below command to open the VSCode from command line.

cd \web part folder\
code .

Based on my web part name, there is a property file created to the store the properties for the parent component. In my case it is ILocalStorageProps.ts. Copy the content and delete the file, paste the content in the LocalStorage.tsx file and change the import reference on the tsx and webpart.ts file. Open your webpart.ts file and copy-paste the below code along with the other code in the file, here we are setting up the pnp with the current context.

import { sp } from "@pnp/sp";

Copy-paste the below code under the default class

public onInit(): Promise<void> {
        return super.onInit().then(_ => {
            sp.setup(this.context);
        });
    }

Navigate to your webpart.tsx file and copy-paste the below code.

import * as React from 'react';
import styles from './LocalStorage.module.scss';
import { DefaultButton } from 'office-ui-fabric-react/lib/Button';
import { sp } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/site-users";
import { ISiteUserInfo } from '@pnp/sp/site-users/types';
import { PnPClientStorage, dateAdd } from '@pnp/common';

const pnpStorage = new PnPClientStorage();

export interface ILocalStorageProps {
    description: string;
}

export interface ILocalStorageState {
    userinfo: ISiteUserInfo;
}

export default class LocalStorage extends React.Component<ILocalStorageProps, ILocalStorageState> {

    constructor(props: ILocalStorageProps) {
        super(props);
        this.state = {
            userinfo: null
        };
    }

    public _storeCurrentUserInfo = async () => {
        let currentUserInfo: ISiteUserInfo = pnpStorage.local.get("PnP_UserInfo");
        if (!currentUserInfo) {
            currentUserInfo = await sp.web.currentUser.get();
            pnpStorage.local.put('PnP_UserInfo', currentUserInfo, dateAdd(new Date(), 'hour', 1));
        }
    }

    public _getStoredUserInfo = async () => {
        let currentUserInfo: ISiteUserInfo = pnpStorage.local.get("PnP_UserInfo");
        if (currentUserInfo) this.setState({ userinfo: currentUserInfo });
        else this.setState({ userinfo: null });
    }

    public componentDidMount() {
        pnpStorage.local.deleteExpired();
    }

    public render(): React.ReactElement<ILocalStorageProps> {        
        return (
            <div className={styles.localStorage}>
                <div className={styles.container}>
                    <div className={styles.row}>
                        <div className={styles.column}>
                            <DefaultButton text="Store User Info" onClick={this._storeCurrentUserInfo} />
                            <DefaultButton text="Get User Info from Storage" onClick={this._getStoredUserInfo} />
                            <div style={{ display: 'inline-flex' }}>
                                {this.state.userinfo ? (
                                    <div>
                                        <p>Title: {this.state.userinfo.Title}</p>
                                        <p>EMail: {this.state.userinfo.Email}</p>
                                    </div>
                                ) : (
                                        <div>{"Click the button 'Store User Info' to store the user information!"}</div>
                                    )}
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

Let us see what we have done in the above code.

Note: We have used the local storage in this sample, there is also another storage option named session storage which is not covered in this article. More information can be found in the link here.

  1. We have used the selective imports concept of PnP to import the sp, web and site-users object. We have also imported PnPClientStorage and dateAdd from @pnp/common
  2. We have declared a state interface to hold the user information to display the data in a div.
  3. We have created 2 methods,
    • _storeCurrentUserInfo – Store the current logged in user information to the local storage. The method will check whether the information is already stored or not, if not then it is fetched from SharePoint and stored in the storage.
    • _getStoredUserInfo – To display the information from the local storage in a div. This method will always pull the information from the storage.
  4. We have declared a componentDidMount method and deleted all the expired values that are stored in the cache. This is the best practice recommended from the PnP team to avoid overloading of the storage or to leave the unwanted data. We can also automate this by using CacheExpirationInterval, the downside of this implementation is that there will be settimeout method triggered to clear the expired storage.
  5. We have declared two buttons to trigger the above mentioned methods.

Preview

Once the solution is ran, you can check your browser console to check whether the information is stored or not.

Source Code

The source code along with other samples can be found in the below github link.

SPFx-Demos

Happy Coding…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s