mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Wrap all calls to localStorage/sessionStorage to avoid potential runtime errors
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import nullthrows from 'nullthrows';
|
||||
import { installHook } from 'src/hook';
|
||||
import { LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY } from 'src/constants';
|
||||
import { localStorageGetItem } from 'src/storage';
|
||||
|
||||
function injectCode(code) {
|
||||
const script = document.createElement('script');
|
||||
@@ -63,7 +64,7 @@ window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeSet = Set;
|
||||
`;
|
||||
|
||||
// If we have just reloaded to profile, we need to inject the renderer interface before the app loads.
|
||||
if (localStorage.getItem(LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true') {
|
||||
if (localStorageGetItem(LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true') {
|
||||
const rendererURL = chrome.runtime.getURL('build/renderer.js');
|
||||
let rendererCode;
|
||||
|
||||
|
||||
@@ -11,6 +11,11 @@ import {
|
||||
getBrowserTheme,
|
||||
} from './utils';
|
||||
import { getSavedComponentFilters } from 'src/utils';
|
||||
import {
|
||||
localStorageGetItem,
|
||||
localStorageRemoveItem,
|
||||
localStorageSetItem,
|
||||
} from 'src/storage';
|
||||
import DevTools from 'src/devtools/views/DevTools';
|
||||
|
||||
const LOCAL_STORAGE_SUPPORTS_PROFILING_KEY =
|
||||
@@ -86,7 +91,7 @@ function createPanelIfReactLoaded() {
|
||||
},
|
||||
});
|
||||
bridge.addListener('reloadAppForProfiling', () => {
|
||||
localStorage.setItem(LOCAL_STORAGE_SUPPORTS_PROFILING_KEY, 'true');
|
||||
localStorageSetItem(LOCAL_STORAGE_SUPPORTS_PROFILING_KEY, 'true');
|
||||
chrome.devtools.inspectedWindow.eval('window.location.reload();');
|
||||
});
|
||||
bridge.addListener('captureScreenshot', ({ commitIndex, rootID }) => {
|
||||
@@ -109,11 +114,11 @@ function createPanelIfReactLoaded() {
|
||||
let isProfiling = false;
|
||||
let supportsProfiling = false;
|
||||
if (
|
||||
localStorage.getItem(LOCAL_STORAGE_SUPPORTS_PROFILING_KEY) === 'true'
|
||||
localStorageGetItem(LOCAL_STORAGE_SUPPORTS_PROFILING_KEY) === 'true'
|
||||
) {
|
||||
supportsProfiling = true;
|
||||
isProfiling = true;
|
||||
localStorage.removeItem(LOCAL_STORAGE_SUPPORTS_PROFILING_KEY);
|
||||
localStorageRemoveItem(LOCAL_STORAGE_SUPPORTS_PROFILING_KEY);
|
||||
}
|
||||
|
||||
const browserName = getBrowserName();
|
||||
|
||||
+23
-19
@@ -8,6 +8,14 @@ import {
|
||||
SESSION_STORAGE_LAST_SELECTION_KEY,
|
||||
__DEBUG__,
|
||||
} from '../constants';
|
||||
import {
|
||||
localStorageGetItem,
|
||||
localStorageRemoveItem,
|
||||
localStorageSetItem,
|
||||
sessionStorageGetItem,
|
||||
sessionStorageRemoveItem,
|
||||
sessionStorageSetItem,
|
||||
} from 'src/storage';
|
||||
import { hideOverlay, showOverlay } from './views/Highlighter';
|
||||
|
||||
import type {
|
||||
@@ -71,19 +79,17 @@ export default class Agent extends EventEmitter {
|
||||
constructor(bridge: Bridge) {
|
||||
super();
|
||||
|
||||
if (localStorage.getItem(LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true') {
|
||||
if (localStorageGetItem(LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true') {
|
||||
this._isProfiling = true;
|
||||
|
||||
localStorage.removeItem(LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY);
|
||||
localStorageRemoveItem(LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY);
|
||||
}
|
||||
|
||||
if (typeof sessionStorage !== 'undefined') {
|
||||
const persistedSelectionString = sessionStorage.getItem(
|
||||
SESSION_STORAGE_LAST_SELECTION_KEY
|
||||
);
|
||||
if (persistedSelectionString != null) {
|
||||
this._persistedSelection = JSON.parse(persistedSelectionString);
|
||||
}
|
||||
const persistedSelectionString = sessionStorageGetItem(
|
||||
SESSION_STORAGE_LAST_SELECTION_KEY
|
||||
);
|
||||
if (persistedSelectionString != null) {
|
||||
this._persistedSelection = JSON.parse(persistedSelectionString);
|
||||
}
|
||||
|
||||
this._bridge = bridge;
|
||||
@@ -237,7 +243,7 @@ export default class Agent extends EventEmitter {
|
||||
};
|
||||
|
||||
reloadAndProfile = () => {
|
||||
localStorage.setItem(LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY, 'true');
|
||||
localStorageSetItem(LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY, 'true');
|
||||
|
||||
// This code path should only be hit if the shell has explicitly told the Store that it supports profiling.
|
||||
// In that case, the shell must also listen for this specific message to know when it needs to reload the app.
|
||||
@@ -547,15 +553,13 @@ export default class Agent extends EventEmitter {
|
||||
// This is why we need the defensive checks here.
|
||||
const renderer = this._rendererInterfaces[rendererID];
|
||||
const path = renderer != null ? renderer.getPathForElement(id) : null;
|
||||
if (typeof sessionStorage !== 'undefined') {
|
||||
if (path !== null) {
|
||||
sessionStorage.setItem(
|
||||
SESSION_STORAGE_LAST_SELECTION_KEY,
|
||||
JSON.stringify(({ rendererID, path }: PersistedSelection))
|
||||
);
|
||||
} else {
|
||||
sessionStorage.removeItem(SESSION_STORAGE_LAST_SELECTION_KEY);
|
||||
}
|
||||
if (path !== null) {
|
||||
sessionStorageSetItem(
|
||||
SESSION_STORAGE_LAST_SELECTION_KEY,
|
||||
JSON.stringify(({ rendererID, path }: PersistedSelection))
|
||||
);
|
||||
} else {
|
||||
sessionStorageRemoveItem(SESSION_STORAGE_LAST_SELECTION_KEY);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
getUID,
|
||||
utfEncodeString,
|
||||
} from 'src/utils';
|
||||
import { localStorageGetItem } from 'src/storage';
|
||||
import { cleanForBridge, copyWithSet, setInObject } from './utils';
|
||||
import {
|
||||
__DEBUG__,
|
||||
@@ -2200,7 +2201,8 @@ export function attach(
|
||||
}
|
||||
|
||||
// Automatically start profiling so that we don't miss timing info from initial "mount".
|
||||
if (localStorage.getItem(LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true') {
|
||||
// TODO This doens't seem right
|
||||
if (localStorageGetItem(LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true') {
|
||||
startProfiling();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
separateDisplayNameAndHOCs,
|
||||
utfDecodeString,
|
||||
} from '../utils';
|
||||
import { localStorageGetItem, localStorageSetItem } from '../storage';
|
||||
import { __DEBUG__ } from '../constants';
|
||||
import { printStore } from 'src/__tests__/storeSerializer';
|
||||
import ProfilerStore from './ProfilerStore';
|
||||
@@ -110,7 +111,7 @@ export default class Store extends EventEmitter {
|
||||
|
||||
// Default this setting to true unless otherwise specified.
|
||||
this._collapseNodesByDefault =
|
||||
localStorage.getItem(LOCAL_STORAGE_COLLAPSE_ROOTS_BY_DEFAULT_KEY) !==
|
||||
localStorageGetItem(LOCAL_STORAGE_COLLAPSE_ROOTS_BY_DEFAULT_KEY) !==
|
||||
'false';
|
||||
|
||||
this._componentFilters = getSavedComponentFilters();
|
||||
@@ -127,8 +128,7 @@ export default class Store extends EventEmitter {
|
||||
if (supportsCaptureScreenshots) {
|
||||
this._supportsCaptureScreenshots = true;
|
||||
this._captureScreenshots =
|
||||
localStorage.getItem(LOCAL_STORAGE_CAPTURE_SCREENSHOTS_KEY) ===
|
||||
'true';
|
||||
localStorageGetItem(LOCAL_STORAGE_CAPTURE_SCREENSHOTS_KEY) === 'true';
|
||||
}
|
||||
if (supportsProfiling) {
|
||||
this._supportsProfiling = true;
|
||||
@@ -184,7 +184,7 @@ export default class Store extends EventEmitter {
|
||||
set captureScreenshots(value: boolean): void {
|
||||
this._captureScreenshots = value;
|
||||
|
||||
localStorage.setItem(
|
||||
localStorageSetItem(
|
||||
LOCAL_STORAGE_CAPTURE_SCREENSHOTS_KEY,
|
||||
value ? 'true' : 'false'
|
||||
);
|
||||
@@ -198,7 +198,7 @@ export default class Store extends EventEmitter {
|
||||
set collapseNodesByDefault(value: boolean): void {
|
||||
this._collapseNodesByDefault = value;
|
||||
|
||||
localStorage.setItem(
|
||||
localStorageSetItem(
|
||||
LOCAL_STORAGE_COLLAPSE_ROOTS_BY_DEFAULT_KEY,
|
||||
value ? 'true' : 'false'
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import throttle from 'lodash.throttle';
|
||||
import { useCallback, useEffect, useLayoutEffect, useState } from 'react';
|
||||
import { localStorageGetItem, localStorageSetItem } from 'src/storage';
|
||||
|
||||
export function useIsOverflowing(
|
||||
containerRef: { current: HTMLDivElement | null },
|
||||
@@ -42,7 +43,7 @@ export function useLocalStorage<T>(
|
||||
): [T, (value: T | (() => T)) => void] {
|
||||
const getValueFromLocalStorage = useCallback(() => {
|
||||
try {
|
||||
const item = window.localStorage.getItem(key);
|
||||
const item = localStorageGetItem(key);
|
||||
if (item != null) {
|
||||
return JSON.parse(item);
|
||||
}
|
||||
@@ -64,7 +65,7 @@ export function useLocalStorage<T>(
|
||||
const valueToStore =
|
||||
value instanceof Function ? (value: any)(storedValue) : value;
|
||||
setStoredValue(valueToStore);
|
||||
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
||||
localStorageSetItem(key, JSON.stringify(valueToStore));
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// @flow
|
||||
|
||||
export function localStorageGetItem(key: string): any {
|
||||
try {
|
||||
return localStorage.getItem(key);
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function localStorageRemoveItem(key: string): void {
|
||||
try {
|
||||
localStorage.removeItem(key);
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
export function localStorageSetItem(key: string, value: any): void {
|
||||
try {
|
||||
return localStorage.setItem(key, value);
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
export function sessionStorageGetItem(key: string): any {
|
||||
try {
|
||||
return sessionStorage.getItem(key);
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function sessionStorageRemoveItem(key: string): void {
|
||||
try {
|
||||
sessionStorage.removeItem(key);
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
export function sessionStorageSetItem(key: string, value: any): void {
|
||||
try {
|
||||
return sessionStorage.setItem(key, value);
|
||||
} catch (error) {}
|
||||
}
|
||||
+3
-2
@@ -9,6 +9,7 @@ import {
|
||||
ElementTypeFunction,
|
||||
ElementTypeMemo,
|
||||
} from 'src/types';
|
||||
import { localStorageGetItem, localStorageSetItem } from './storage';
|
||||
|
||||
import type { ComponentFilter, ElementType } from './types';
|
||||
|
||||
@@ -82,7 +83,7 @@ export function getDefaultComponentFilters(): Array<ComponentFilter> {
|
||||
|
||||
export function getSavedComponentFilters(): Array<ComponentFilter> {
|
||||
try {
|
||||
const raw = localStorage.getItem(LOCAL_STORAGE_FILTER_PREFERENCES_KEY);
|
||||
const raw = localStorageGetItem(LOCAL_STORAGE_FILTER_PREFERENCES_KEY);
|
||||
if (raw != null) {
|
||||
return JSON.parse(raw);
|
||||
}
|
||||
@@ -93,7 +94,7 @@ export function getSavedComponentFilters(): Array<ComponentFilter> {
|
||||
export function saveComponentFilters(
|
||||
componentFilters: Array<ComponentFilter>
|
||||
): void {
|
||||
localStorage.setItem(
|
||||
localStorageSetItem(
|
||||
LOCAL_STORAGE_FILTER_PREFERENCES_KEY,
|
||||
JSON.stringify(componentFilters)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user