diff --git a/desktop/.eslintrc.js b/desktop/.eslintrc.js index b22a1fb01..a4f9d8cdc 100644 --- a/desktop/.eslintrc.js +++ b/desktop/.eslintrc.js @@ -46,10 +46,13 @@ module.exports = { '@typescript-eslint', 'import', 'node', + 'react-hooks', ], rules: { // disable rules from eslint-config-fbjs 'react/react-in-jsx-scope': 0, // not needed with our metro implementation + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', 'no-new': 0, // new keyword needed e.g. new Notification 'no-catch-shadow': 0, // only relevant for IE8 and below 'no-bitwise': 0, // bitwise operations needed in some places diff --git a/desktop/app/src/chrome/plugin-manager/PluginInstaller.tsx b/desktop/app/src/chrome/plugin-manager/PluginInstaller.tsx index e92fd7bc0..e17104fdf 100644 --- a/desktop/app/src/chrome/plugin-manager/PluginInstaller.tsx +++ b/desktop/app/src/chrome/plugin-manager/PluginInstaller.tsx @@ -142,7 +142,7 @@ export function annotatePluginsWithUpdates( return new Map(annotated); } -const PluginInstaller = function props(props: Props) { +const PluginInstaller = function (props: Props) { const [restartRequired, setRestartRequired] = useState(false); const [query, setQuery] = useState(''); diff --git a/desktop/app/src/ui/components/Tabs.tsx b/desktop/app/src/ui/components/Tabs.tsx index d0b8606a8..bb1d94028 100644 --- a/desktop/app/src/ui/components/Tabs.tsx +++ b/desktop/app/src/ui/components/Tabs.tsx @@ -165,8 +165,10 @@ export default function Tabs(props: { */ classic?: boolean; }) { - const tabsContainer = - props.classic === true ? false : useContext(TabsContext); + let tabsContainer = useContext(TabsContext); + if (props.classic === true) { + tabsContainer = false; + } const {onActive} = props; const active: string | undefined = diff --git a/desktop/package.json b/desktop/package.json index 5651890f1..f3b9c3a0f 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -172,6 +172,7 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.1.2", "eslint-plugin-react": "^7.20.0", + "eslint-plugin-react-hooks": "^4.0.2", "eslint-plugin-relay": "^1.4.1", "express": "^4.15.2", "flipper-babel-transformer": "0.44.0", diff --git a/desktop/plugins/layout/InspectorSidebar.tsx b/desktop/plugins/layout/InspectorSidebar.tsx index 877a6e007..1b26f6c93 100644 --- a/desktop/plugins/layout/InspectorSidebar.tsx +++ b/desktop/plugins/layout/InspectorSidebar.tsx @@ -98,56 +98,55 @@ type Props = { const Sidebar: React.FC = (props: Props) => { const {element} = props; - if (!element || !element.data) { - return No data; - } const [sectionDefs, sectionKeys] = useMemo(() => { const sectionKeys = []; const sectionDefs = []; - for (const key in element.data) { - if (key === 'Extra Sections') { - for (const extraSection in element.data[key]) { - const section = element.data[key][extraSection]; - let data = {}; + if (element && element.data) + for (const key in element.data) { + if (key === 'Extra Sections') { + for (const extraSection in element.data[key]) { + const section = element.data[key][extraSection]; + let data = {}; - // data might be sent as stringified JSON, we want to parse it for a nicer persentation. - if (typeof section === 'string') { - try { - data = JSON.parse(section); - } catch (e) { - // data was not a valid JSON, type is required to be an object - console.error( - `ElementsInspector unable to parse extra section: ${extraSection}`, - ); - data = {}; + // data might be sent as stringified JSON, we want to parse it for a nicer persentation. + if (typeof section === 'string') { + try { + data = JSON.parse(section); + } catch (e) { + // data was not a valid JSON, type is required to be an object + console.error( + `ElementsInspector unable to parse extra section: ${extraSection}`, + ); + data = {}; + } + } else { + data = section; } - } else { - data = section; + sectionKeys.push(kebabCase(extraSection)); + sectionDefs.push({ + key: extraSection, + id: extraSection, + data: data, + }); } - sectionKeys.push(kebabCase(extraSection)); + } else { + sectionKeys.push(kebabCase(key)); sectionDefs.push({ - key: extraSection, - id: extraSection, - data: data, + key, + id: key, + data: element.data[key], }); } - } else { - sectionKeys.push(kebabCase(key)); - sectionDefs.push({ - key, - id: key, - data: element.data[key], - }); } - } return [sectionDefs, sectionKeys]; }, [props.element]); const sections: Array = ( (SidebarExtensions && + element?.data && SidebarExtensions.map((ext) => ext(props.client, props.realClient, element, props.logger), )) || @@ -169,6 +168,10 @@ const Sidebar: React.FC = (props: Props) => { props.logger.track('usage', `layout-sidebar-extension:${key}:loaded`), ); }, [props.element?.data]); + + if (!element || !element.data) { + return No data; + } return <>{sections}; }; diff --git a/desktop/yarn.lock b/desktop/yarn.lock index b11cd7036..2c2484cfe 100644 --- a/desktop/yarn.lock +++ b/desktop/yarn.lock @@ -5312,6 +5312,11 @@ eslint-plugin-prettier@^3.1.1, eslint-plugin-prettier@^3.1.2: dependencies: prettier-linter-helpers "^1.0.0" +eslint-plugin-react-hooks@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.0.2.tgz#03700ca761eacc1b6436074c456f90a8e331ff28" + integrity sha512-kAMRjNztrLW1rK+81X1NwMB2LqG+nc7Q8AibnG8/VyWhQK8SP6JotCFG+HL4u1EjziplxVz4jARdR8gGk8pLDA== + eslint-plugin-react@^7.20.0: version "7.20.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.20.0.tgz#f98712f0a5e57dfd3e5542ef0604b8739cd47be3"