Share data between SPFx webpart

Introduction 


 While developing multiple web parts on a same page, there often a scenario arises for the developer to request a same data from a source which is already requested by another web part. While making a subsequent call to the same source is possible, but it is highly recommended to store the already received value from the source in a place where other web part can reuse the value, instead of making repeated calls requesting the same information.

By following this practice of sharing data between the client side web part of the same page, one can significantly increase the performance  of the page & reduce the network traffic.

Pictorial Representation of Architectural Flow


Below is a architectural flow which is explained in detail in this article.

  1. Two web part requires similar information from a SharePoint List. (e.g : First web part need to e Items in the list and second webpart need to display the Authors from the list)
  2. Data is pulled from the list as is saved in the session storage.
  3. Instead of making subsequent call to the same list requesting same data, value is being read from the session storage once stored.

Getting started


Create two SPFx webpart

Refer this article to create a SPFx webpart, Provide the name of the webpart as "ListItems" & "Authors" and choose React framework which we will use in this article.

Include PnP JS Library

We will use PnP JS library to get items from list and to to store these values in Session storage. This will help us making our solution look cleaner as we need to write much less lines of code while comparing with the typical calling of SharePoint REST api using HTTPClient. We will also take advantage of entity merging using PnP JS.

Run the below command to setup PnP JS Library in your project

npm install @pnp/logging @pnp/common @pnp/odata @pnp/sp @pnp/graph --save

Get Items & Put it in Session Storage using PnP JS

We will go through a series of action to perform the operation

Define interface

For defining the interface for the list item to retrieved, we will create a folder under src folder with the name Contract and a file name IListItems.ts. Add the below code to this ts file.

Here we need List item ID, Title and Created by fields. Hence we will define the interface based on it.

export interface IListItem {
    Id: number;
    Title: string;
    Author: { Title };
}

Create Service

By creating a service, we will store the item details received from the list in session storage for other webparts on the page to use it.

Create a folder under src folder named service and add a file name ListItemService.ts. Add the below code in the ts file.

01.import { IListItem } from '../Contract/IListItem';
02.import { sp, spODataEntityArray, Item } from "@pnp/sp";
03.import { PnPClientStorage } from "@pnp/common";
04.import { Features } from '@pnp/sp/src/features';
05. 
06.export class ListitemService {
07.    private static storageKey: string = 'listItemsKey';
08.    private static listItems: IListItem[] = [];
09.    private static storage = new  PnPClientStorage();
10. 
11.    public static getListItems(): Promise<IListItem[]> {
12.        return new  Promise<IListItem[]>(async (resolve: (newListItems: IListItem[]) => void, reject: (error: any) => void) => {
13.            const loadedData = this.storage.session.get(this.storageKey);
14.            let items: IListItem[] = null;
15.            if ((window as any).loadingData) {
16.                window.setTimeout((): void => {
17.                    this.getListItems().then((newListItems: IListItem[]): void => {
18.                        resolve(newListItems);
19.                    });
20.                }, 50);
21.            }
22.            else {
23.                if (!loadedData) {
24.                    (window as any).loadingData = true;
25.                    items = await sp.web.lists.getByTitle("Testlist").items.expand('Author').select("Id", "Title",  "Author/Title").get(spODataEntityArray<Item, IListItem>(Item));
26.                    this.storage.session.put(this.storageKey, items);
27.                    console.log("from SharePoint list");
28.                    (window as any).loadingData = false;
29.                }
30.                else {
31.                    console.log("from Session storage");
32.                    items = loadedData;
33.                }
34.                resolve(items);
35.            }
36.        });
37.    }
38. 
39.}

Get Items using PnP JS

On Line 25, we are using an Await/Aysnc call to get list item from a list named "TestList".

Entity Merging

On Line 25, We are specifying the Entity format by passing the interface we created in the previous step to the spODataEntityArray. This allows to get the values in the predefined format instead of creating another function to create or make changes entities received. 

Store & Retrieve value via Session storage using PnP JS

On Line 26, we are storing the item details received in the session storage using PnP Client storage module. With a key to identify & retrieve our stored data afterwards.
For this, we first initialize the PnPClientStorage ``on line ``9, then use ``this``.storage.session.put(``this``.storageKey, items) to store the values 
On Line 13, we are analyzing whether session storage is present or not. if present, it can be utilized by other webpart on the same page.

In order to store the value in local storage, use local inplace of session. so the code would be, this.storage.local(key,value);

Call the service 

We will call the service before rendering the webpart inorder to get the list of items to be displayed. For this, we will replace the default render function under ListItemWebpart.ts located under src > webparts > Listitems with the below code.

Include the following imports mentioned below

import { IListItem } from '../../Contract/IListItem';
import { ListitemService } from '../../Services/ListItemService';
public render(): void {
    this.context.statusRenderer.displayLoadingIndicator(this.domElement, '');
    ListitemService.getListItems()
      .then((listItem: IListItem[]): void => {
        const element: React.ReactElement<IListItemsProps> = React.createElement(
          ListItems,
          {
            ListItem: listItem
          }
        );
        this.context.statusRenderer.clearLoadingIndicator(this.domElement);
        ReactDom.render(element, this.domElement);
      });
}

Similarly, perform the same steps for Author web part as well. In case of any issue, download the solution from the technet gallery, link provided in the last section.

Run the below command and add the two web part in SharePoint workbench or using deploy & add the app method.

gulp serve

Once both the web parts are added to the page, we can see that after initial response/data received, all the subsequent value is being taken from the session storage. This helps in reducing multiple calls requesting the same information.
 

Conclusion


Thus, we learned how data can be shared between SPFx webparts which are placed on the same page.

Download this solution


This solution can be downloaded from Technet Gallery

See Also