Add ability to delete, or choose not to rehydrate the store in onRehydrateStorage

See original GitHub issue

This might have overlap with the issue #267, however this isn’t fully explained in that.

I notice there isn’t a great way to handle conditional persisted state rehydration.

In the onRehydrateStorage it would be nice to be able to either return state or throw an Error / return directly to not rehydrate the storage.

A little example; here I want to check if a cookie is still present, a JWT that expires after a week, and then choose not to rehydrate, the only option I found is below, to delete the localStorage key.

onRehydrateStorage: () => {
  if (!hasJWT()) {
    console.log("No JWT Present, Delete State");

    localStorage.removeItem("web3-store");
  }
},

An ideal API would be,

onRehydrateStorage: (state) => {
  if (hasJWT()) {
    return state
  }
  
  return false
}

Let me know if I’m missing something!

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:4
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
gabimonchacommented, Feb 21, 2022

@mirshko @barbogast @AnatoleLucet

How I managed to make zustand persist accept asynchronous storage.

First of all, I want to acknowledge the simplicity with which this library was created, otherwise I wouldn’t have the confidence to look into its source code and try a workaround. Big up team! 🙌🏼 My hopes are that this is not just a hack, but serves as an inspiration to others or maybe even a good fix for this amazing library.

Problem

As I said earlier, my issue was that zustand’s persist middleware was overwriting the storage on hydrate, because there was no “initial” way of making it to or check for a condition before overwriting the storage or wait for a trigger to start hydration, before getting the storage - in case one has an asynchronous storage ( the edge case of an encrypted storage which is available after the user successfully enters the PIN / Password / biometrics ( most cases happen in React Native).

Solution

  1. Because I am using the onRehydrateStorage method to know when my hydration ends, I configured my persist store with empty options in order to block any storage overwrite or to solve any type error that comes if my getStorage is an async function.
      onRehydrateStorage: () => async () => {},
      getStorage: undefined,
  1. Then, after I get my storage initialised, I call api.persist.setOptions overwriting in the process the empty getStorage and onRehydrateStorage with the methods that I need, and then I trigger a rehydration with api.persist.rehydrate().

Caveats

In order for this workaround to be successful, I had to take the unorthodox way and patch the library. Initial storage hydration is stopped, but at the same time makes any persist api methods unavailable as these are set later right before hydration, after the guard case where the middleware checks if the storage is set

In the patch, I’m moving the storage guard case after the api.persist property is set and before hydrate is called. Of course, this throws TypeError: Cannot read property 'setItem' of undefined because now persist will continue to call setItem on initialisation and for this I had to add an additional guard case in my patch to check if the storage exists there.

diff --git a/node_modules/zustand/middleware.js b/node_modules/zustand/middleware.js
index 4cb6011..21e052f 100644
--- a/node_modules/zustand/middleware.js
+++ b/node_modules/zustand/middleware.js
@@ -317,18 +317,11 @@ var persist = function persist(config, baseOptions) {
       storage = options.getStorage();
     } catch (e) {}
 
-    if (!storage) {
-      return config(function () {
-        console.warn("[zustand persist middleware] Unable to update item '" + options.name + "', the given storage is currently unavailable.");
-        set.apply(void 0, arguments);
-      }, get, api);
-    } else if (!storage.removeItem) {
-      console.warn("[zustand persist middleware] The given storage for item '" + options.name + "' does not contain a 'removeItem' method, which will be required in v4.");
-    }
 
     var thenableSerialize = toThenable(options.serialize);
 
     var setItem = function setItem() {
+      if (!storage) return;
       var state = options.partialize(_extends({}, get()));
 
       if (options.whitelist) {
@@ -445,6 +438,14 @@ var persist = function persist(config, baseOptions) {
         };
       }
     };
+    if (!storage) {
+      return config(function () {
+        console.warn("[zustand persist middleware] Unable to update item '" + options.name + "', the given storage is currently unavailable.");
+        set.apply(void 0, arguments);
+      }, get, api);
+    } else if (!storage.removeItem) {
+      console.warn("[zustand persist middleware] The given storage for item '" + options.name + "' does not contain a 'removeItem' method, which will be required in v4.");
+    }
     hydrate();
     return stateFromStorage || configResult;
   };
0reactions
dai-shicommented, Dec 5, 2022

Can anyone help what should be implemented for this issue?

Read more comments on GitHub >

github_iconTop Results From Across the Web

zustand - Bountysource
Add ability to delete, or choose not to rehydrate the store in ... In the onRehydrateStorage it would be nice to be able...
Read more >
React Redux Persist is rehydrating, but no stored data is ...
I'm testing with a store that doesn't have any saga in the middle, when I trigger an action, the data is updated, I...
Read more >
How to Save State to LocalStorage & Persist on Refresh with ...
Step 2: Storing React state in localStorage. Now that we're successfully hiding our banner with state, we want to make sure when someone ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found