mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Add listen parameter to usePersistedState hook (#5134)
GitOrigin-RevId: d40f942164403a31ffbb10336227eef59a57febf
This commit is contained in:
parent
388d9c0f1e
commit
e76b7696da
2 changed files with 69 additions and 2 deletions
|
@ -1,7 +1,14 @@
|
|||
import { useState, useCallback } from 'react'
|
||||
import { useState, useCallback, useEffect } from 'react'
|
||||
import localStorage from '../../infrastructure/local-storage'
|
||||
|
||||
function usePersistedState(key, defaultValue) {
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {any} [defaultValue]
|
||||
* @param {boolean} [listen]
|
||||
*
|
||||
* @returns {[any, function]}
|
||||
*/
|
||||
function usePersistedState(key, defaultValue, listen = false) {
|
||||
const [value, setValue] = useState(() => {
|
||||
return localStorage.getItem(key) ?? defaultValue
|
||||
})
|
||||
|
@ -24,6 +31,24 @@ function usePersistedState(key, defaultValue) {
|
|||
[key, defaultValue]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (listen) {
|
||||
const listener = event => {
|
||||
if (event.key === key) {
|
||||
// note: this value is read via getItem rather than from event.newValue
|
||||
// because getItem handles deserializing the JSON that's stored in localStorage.
|
||||
setValue(localStorage.getItem(key))
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('storage', listener)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('storage', listener)
|
||||
}
|
||||
}
|
||||
}, [key, listen])
|
||||
|
||||
return [value, updateFunction]
|
||||
}
|
||||
|
||||
|
|
|
@ -138,4 +138,46 @@ describe('usePersistedState', function () {
|
|||
|
||||
expect(localStorage.getItem(key)).to.equal('foobar')
|
||||
})
|
||||
|
||||
it('handles syncing values via storage event', async function () {
|
||||
const key = 'test:sync'
|
||||
localStorage.setItem(key, 'foo')
|
||||
expect(window.Storage.prototype.setItem).to.have.callCount(1)
|
||||
|
||||
// listen for storage events
|
||||
const storageEventListener = sinon.stub()
|
||||
window.addEventListener('storage', storageEventListener)
|
||||
|
||||
const Test = () => {
|
||||
const [value, setValue] = usePersistedState(key, 'bar', true)
|
||||
|
||||
useEffect(() => {
|
||||
setValue('baz')
|
||||
}, [setValue])
|
||||
|
||||
return <div>{value}</div>
|
||||
}
|
||||
|
||||
render(<Test />)
|
||||
|
||||
screen.getByText('baz')
|
||||
|
||||
expect(window.Storage.prototype.getItem).to.have.callCount(1)
|
||||
expect(window.Storage.prototype.removeItem).to.have.callCount(0)
|
||||
expect(window.Storage.prototype.setItem).to.have.callCount(2)
|
||||
|
||||
expect(localStorage.getItem(key)).to.equal('baz')
|
||||
|
||||
expect(storageEventListener).to.have.callCount(0)
|
||||
|
||||
// set the new value in localStorage
|
||||
localStorage.setItem(key, 'cat')
|
||||
|
||||
// dispatch a "storage" event and check that it's picked up by the hook
|
||||
window.dispatchEvent(new StorageEvent('storage', { key }))
|
||||
|
||||
await screen.findByText('cat')
|
||||
|
||||
expect(storageEventListener).to.have.callCount(1)
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue