Skip to content

Commit

Permalink
fix: useexternalstore
Browse files Browse the repository at this point in the history
  • Loading branch information
nahoc committed Oct 2, 2024
1 parent 4ab0d5b commit 67973a0
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 59 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ https://www.npmjs.com/package/@risc0/ui

| Statements | Branches | Functions | Lines |
| --------------------------- | ----------------------- | ------------------------- | ----------------- |
| ![Statements](https://img.shields.io/badge/statements-40.88%25-red.svg?style=flat) | ![Branches](https://img.shields.io/badge/branches-81.72%25-yellow.svg?style=flat) | ![Functions](https://img.shields.io/badge/functions-75.47%25-red.svg?style=flat) | ![Lines](https://img.shields.io/badge/lines-40.88%25-red.svg?style=flat) |
| ![Statements](https://img.shields.io/badge/statements-41.51%25-red.svg?style=flat) | ![Branches](https://img.shields.io/badge/branches-81.72%25-yellow.svg?style=flat) | ![Functions](https://img.shields.io/badge/functions-75.47%25-red.svg?style=flat) | ![Lines](https://img.shields.io/badge/lines-41.51%25-red.svg?style=flat) |
60 changes: 15 additions & 45 deletions hooks/use-local-storage.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
"use client";

import { isEqual, isFunction } from "radash";
import { type Dispatch, type SetStateAction, useEffect, useRef, useState } from "react";
import { isFunction } from "radash";
import { type SetStateAction, useRef, useSyncExternalStore } from "react";
import { parseJson } from "../utils/parse-json";
import { useEventListener } from "./use-event-listener";

function isNil(val: unknown) {
return val == null;
}

export type SetValue<T> = Dispatch<SetStateAction<T>>;
export type SetValue<T> = (value: SetStateAction<T>) => void;

/**
* Creating and read here and using window.setItem for writes. This avoids
Expand Down Expand Up @@ -42,70 +39,43 @@ function isError(value: StorageError | any): value is StorageError {
export function useLocalStorage<T>(key: string, initialValue: T): [T, SetValue<T>] {
const previousValueRef = useRef(initialValue);

// Get from local storage then
// parse stored json or return initialValue
function readValue(): T {
// Prevent build error "window is undefined" but keep keep working
if (typeof window === "undefined") {
return initialValue;
}

const value = readValueFromStorage<T>(key);

return isError(value) || isNil(value) || value === "" ? initialValue : (value as T);
}

// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = useState<T>(readValue);
function subscribe(callback: () => void) {
window.addEventListener("storage", callback);
window.addEventListener("local-storage", callback);
return () => {
window.removeEventListener("storage", callback);
window.removeEventListener("local-storage", callback);
};
}

const storedValue = useSyncExternalStore(subscribe, readValue, () => initialValue);

// Return a wrapped version of useState's setter function that persists the new value to localStorage.
function setValue(value: SetStateAction<T>): void {
// Prevent build error "window is undefined" but keeps working
if (typeof window === "undefined") {
console.warn(`Tried setting localStorage key "${key}" even though environment is not a client`);
return;
}

try {
// Allow value to be a function so we have the same API as useState
const newValue = isFunction(value) ? (value as (prevState: T) => T)(storedValue) : value;

// Save to local storage
window.localStorage.setItem(key, JSON.stringify(newValue));
previousValueRef.current = newValue;

// Save state
setStoredValue(newValue);

// We dispatch a custom event so every useLocalStorage hook are notified
window.dispatchEvent(new Event("local-storage"));
} catch (error) {
console.warn(`Error setting localStorage key "${key}":`, error);
}
}

// biome-ignore lint/correctness/useExhaustiveDependencies: run only once
useEffect(() => {
const newValue = readValue();
setStoredValue(newValue);
previousValueRef.current = newValue;
}, []);

function handleStorageChange() {
const newValue = readValue();

if (isEqual(newValue, previousValueRef.current)) {
return;
}
setStoredValue(newValue);
previousValueRef.current = newValue;
}

// this only works for other documents, not the current one
useEventListener("storage", handleStorageChange);

// this is a custom event, triggered in writeValueToLocalStorage
// See: useLocalStorage()
useEventListener("local-storage", handleStorageChange);

return [storedValue, setValue];
}
26 changes: 13 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@risc0/ui",
"version": "0.0.180",
"version": "0.0.181",
"private": false,
"sideEffects": false,
"type": "module",
Expand All @@ -15,27 +15,27 @@
"story": "ladle serve"
},
"dependencies": {
"@radix-ui/react-avatar": "1.1.0",
"@radix-ui/react-checkbox": "1.1.1",
"@radix-ui/react-avatar": "1.1.1",
"@radix-ui/react-checkbox": "1.1.2",
"@radix-ui/react-dialog": "1.0.5",
"@radix-ui/react-dropdown-menu": "2.1.1",
"@radix-ui/react-dropdown-menu": "2.1.2",
"@radix-ui/react-label": "2.1.0",
"@radix-ui/react-navigation-menu": "1.2.0",
"@radix-ui/react-popover": "1.1.1",
"@radix-ui/react-navigation-menu": "1.2.1",
"@radix-ui/react-popover": "1.1.2",
"@radix-ui/react-progress": "1.1.0",
"@radix-ui/react-radio-group": "1.2.0",
"@radix-ui/react-select": "2.1.1",
"@radix-ui/react-radio-group": "1.2.1",
"@radix-ui/react-select": "2.1.2",
"@radix-ui/react-separator": "1.1.0",
"@radix-ui/react-slider": "1.2.0",
"@radix-ui/react-slider": "1.2.1",
"@radix-ui/react-slot": "1.1.0",
"@radix-ui/react-switch": "1.1.0",
"@radix-ui/react-tabs": "1.1.0",
"@radix-ui/react-tooltip": "1.1.2",
"@radix-ui/react-switch": "1.1.1",
"@radix-ui/react-tabs": "1.1.1",
"@radix-ui/react-tooltip": "1.1.3",
"autoprefixer": "10.4.20",
"class-variance-authority": "0.7.1-canary.2",
"clsx": "2.1.1",
"cmdk": "1.0.0",
"lucide-react": "0.446.0",
"lucide-react": "0.447.0",
"next-themes": "0.3.0",
"radash": "12.1.0",
"react-hook-form": "7.52.2",
Expand Down

0 comments on commit 67973a0

Please sign in to comment.