Search code examples
javascripttypescriptoverridingspfx

Is it safe to override window.sessionStorage.getItem and setItem?


In my SPFx web part I am using an npm package that defines React.js controls that I need. The library is https://github.com/pnp/sp-dev-fx-controls-react, but my question is not strictly related to this library. For specific reasons I need to use an older version of this library. One of the controls I use reads data from the server and caches it in session storage (it's the TaxonomyPicker). Now in my use case, this data can be more than 7MB in size and the code fails where it tries to call setItem(key, value) with this long string. Unfortunately this error leads to the control not rendering.

Since I didn't want to change the (old version of the) library I am using, I decided to override the window.sessionStorage.getItem and setItem methods by functions that compress the string before it is saved and decompress it after it has been read with getItem. I do this only for large strings. Here's my implementation (in TypeScript):

fixSetItemFunc = (): void => {
    const lzPrefix = 'lz:';
    const threshold = 5000;
    if (!this.oldSetItemFunc) {
        this.oldSetItemFunc = window.sessionStorage.setItem.bind(window.sessionStorage);
        const setItem = (key: string, value: string) => {
            let compressedValue: string;
            if (value && value.length > threshold) {
                compressedValue = lzPrefix + LZ.compress(value);
            }
            else {
                compressedValue = value;
            }
            this.oldSetItemFunc(key, compressedValue);
        };
        window.sessionStorage.setItem = setItem;

        this.oldGetItemFunc = window.sessionStorage.getItem.bind(window.sessionStorage);
        const getItem = (key: string) => {
            const value = this.oldGetItemFunc(key);
            let decompressedValue: string;
            if (value && value.length && value.substring(0, lzPrefix.length) === lzPrefix) {
                decompressedValue = LZ.decompress(value.substring(lzPrefix.length));
            }
            else {
                decompressedValue = value;
            }
            return decompressedValue;
        };
        window.sessionStorage.getItem = getItem;
    }
}

Now the interesting thing is that this workaround seems to work. But since session storage can live quite a while and users can navigate away from the page where I add the override, I am wondering if this is in anyway a reliable solution. Because all other code that is run on other SharePoint pages will use my overridden methods after I called fixSetItemFunc() once in my web part. So I would be interested in your thoughts on this.


Solution

  • As you said, this override will apply and could potentially affect all the code on the page, not just your code. Why don't you instead break the long string into fragments and store those fragments as separate keys into the sessionStorage following some smart naming convention for the keys? That way you could easily isolate the logic for handling of large strings to your code only, without having to override a global method.

    Btw, keep in mind that the sessionStorage is an in-memory storage private to the current browser window/tab, so every window/tab will have to maintain its own copy of the data.