Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 1x 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 1x 1x 3x 3x 1x 1x 1x 12x 12x 12x 12x 12x 12x 12x 12x 12x 12x 11x 12x 12x 2x 2x 2x 1x 1x 1x 2x 3x 3x 12x 1x 1x 1x 1x 1x 12x 12x 3x 3x 3x 3x 1x 1x 1x 3x 12x 2x 2x 1x 1x 1x 1x 1x 1x 2x 12x 12x 12x 12x 12x 12x 1x 1x 1x 5x 5x 5x 5x 5x 4x 2x 2x 2x 2x 4x 5x 5x 5x 5x 5x 5x 3x 5x 5x 5x 5x 5x 5x 5x 5x 1x 1x 5x 5x | import { AppContext } from '@/context';
import { cstorage } from '@/utils/storage';
import { use } from 'react';
import { Logger } from '@/utils/Logger';
import { getErrorMessage } from '@/helpers/exceptions';
const logger = new Logger('useContext');
/**
* React v19's use() hook can work with Context directly
*
* Benefits over useContext:
* - No need for separate error handling wrapper
* - Works with Suspense boundaries
* - Cleaner, more direct API
* - Future-proof for React's direction
* @source
*/
export function useAppContext() {
// No need for separate useContext - use() handles it
// The context provider's error handling is sufficient
return use(AppContext);
}
/**
* Promise-based Chrome storage with use() hook
*
* This demonstrates how React v19's use() hook can handle promises directly,
* eliminating the need for useEffect + useState patterns for async data.
*
* Benefits:
* - Direct promise handling without useEffect
* - Automatic Suspense integration
* - Cleaner error boundaries
* - Reduces boilerplate code
* @source
*/
export function useChromeStorage<T>(key: string, defaultValue: T) {
// The use() hook can handle promises directly
// This will suspend the component until the promise resolves
const storedValue = use(
(async () => {
const data = await cstorage.session.get([key]);
// chrome.storage returns untyped data; narrow to the caller's generic T.
return data[key] !== undefined ? (data[key] as T) : defaultValue;
})(),
);
const setValue = (value: T) => {
cstorage.session.set({ [key]: value });
};
return [storedValue, setValue] as const;
}
/**
* Enhanced version with error handling and type safety
* @source
*/
export function useChromeStorageEnhanced<T>(
key: string,
defaultValue: T,
options?: {
storage?: 'session' | 'local';
serializer?: {
serialize: (value: T) => string;
deserialize: (value: string) => T;
};
},
) {
const storage = options?.storage === 'local' ? cstorage.local : cstorage.session;
const { serializer } = options || {};
const storedValue = use(
(async () => {
try {
const data = await storage.get([key]);
const rawValue = data[key];
if (rawValue === undefined) return defaultValue;
if (serializer) {
try {
return serializer.deserialize(rawValue);
} catch (error) {
logger.warn(`Failed to deserialize ${key}: ${getErrorMessage(error)}`, { error });
return defaultValue;
}
}
// chrome.storage returns untyped data; narrow to the caller's generic T.
return rawValue as T;
} catch (error) {
logger.error(`Failed to load ${key} from Chrome storage: ${getErrorMessage(error)}`, {
error,
});
return defaultValue;
}
})(),
);
const setValue = async (value: T) => {
try {
const valueToStore = serializer ? serializer.serialize(value) : value;
await storage.set({ [key]: valueToStore });
} catch (error) {
logger.error(`Failed to save ${key} to Chrome storage: ${getErrorMessage(error)}`, { error });
throw error;
}
};
const removeValue = async () => {
try {
await storage.remove([key]);
} catch (error) {
logger.error(`Failed to remove ${key} from Chrome storage: ${getErrorMessage(error)}`, {
error,
});
throw error;
}
};
return {
value: storedValue,
setValue,
removeValue,
};
}
/**
* Reactive Chrome storage hook that watches for changes
* Uses React v19's use() hook with a custom promise that updates on storage changes
* @source
*/
export function useReactiveChromeStorage<T>(key: string, defaultValue: T) {
// Create a promise that resolves and updates when storage changes
const createStoragePromise = () => {
return new Promise<T>((resolve) => {
// Listen for changes
const listener = (changes: { [key: string]: chrome.storage.StorageChange }) => {
if (changes[key]) {
// chrome.storage change values are untyped; narrow to the caller's generic T.
resolve(
changes[key].newValue !== undefined ? (changes[key].newValue as T) : defaultValue,
);
}
};
cstorage.onChanged.addListener(listener);
// Initial load. The executor must stay synchronous (no async Promise
// executor), so the await runs inside a voided async IIFE; resolve() is
// idempotent, so the first value (initial load or an early change) wins.
void (async () => {
const data = await cstorage.session.get([key]);
// chrome.storage returns untyped data; narrow to the caller's generic T.
resolve(data[key] !== undefined ? (data[key] as T) : defaultValue);
})();
// Cleanup is handled by React's concurrent features
// This is a simplified example - in practice you'd want proper cleanup
});
};
const value = use(createStoragePromise());
const setValue = (newValue: T) => {
cstorage.session.set({ [key]: newValue });
};
return [value, setValue] as const;
}
|