Skip to content

Commit

Permalink
fix: with-redux check for changed storage values (#42)
Browse files Browse the repository at this point in the history
* fix: with-redux import typed hook as type

Change made in response to the following TS error:
'TypedUseSelectorHook' is a type and must be imported using a type-only
import when 'verbatimModuleSyntax' is enabled.

Error shows up when creating a new repository using `pnpm create plasmo
--with-redux`. Fix doesn't affect useAppSelector hook in Counter.tsx.

* fix: with-redux check for changed storage values

Watch callback function will be called on every change in Firefox even
when the value is the same. This commit checks if the value has changed
before calling persistor.resync(). Chrome/Safari already prevented the
listener from being called when the value is the same.

Performance of different approaches:
https://jsperf.app/lezoki

Note that the change object given to the listener can exclude either
oldValues or newValues and that the keys for either can be added/removed
in either time direction. Also, in this particular context, deeply
nested states (beyond newValue.key) will always be strings so
JSON.stringify is unnecessary. Thus, using two for/in loops was the most
performant option.

The performance impact on Chrome/Safari should be negligible. It can be
mitigated further by gating the code for Firefox only but given the
behavior is not defined clearly in any specification documents and thus
subject to change in any of the browsers, this was deemed unmaintainable
in the long term. Object.keys is already called twice on the state
object by redux-persist on resync so this is not a significant extra
amount of work when a resync is needed.

Tested with chrome-mv3, firefox-mv3, and firefox-mv2 (with a temp ID for
Firefox sync storage in a separate repo).
  • Loading branch information
Zweihander-Main authored Sep 22, 2023
1 parent 7077ba3 commit 8a839dc
Showing 1 changed file with 18 additions and 3 deletions.
21 changes: 18 additions & 3 deletions with-redux/store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { combineReducers, configureStore } from "@reduxjs/toolkit"
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"
import { useDispatch, useSelector } from "react-redux"
import type { TypedUseSelectorHook } from "react-redux"
import { syncStorage } from "redux-persist-webextension-storage"

import {
Expand Down Expand Up @@ -60,8 +61,22 @@ export const persistor = persistStore(store)
// This is what makes Redux sync properly with multiple pages
// Open your extension's options page and popup to see it in action
new Storage().watch({
[`persist:${persistConfig.key}`]: () => {
persistor.resync()
[`persist:${persistConfig.key}`]: (change) => {
const { oldValue, newValue } = change
const updatedKeys = []
for (const key in oldValue) {
if (oldValue[key] !== newValue?.[key]) {
updatedKeys.push(key)
}
}
for (const key in newValue) {
if (oldValue?.[key] !== newValue[key]) {
updatedKeys.push(key)
}
}
if (updatedKeys.length > 0) {
persistor.resync()
}
}
})

Expand Down

0 comments on commit 8a839dc

Please sign in to comment.