From c58bc694ee8dc45395336ff9add70b99d0dbaf3a Mon Sep 17 00:00:00 2001 From: Aria Minaei Date: Sat, 31 Dec 2022 22:54:24 +0100 Subject: [PATCH] Fix: Re-render the panels when object identity change This fixes the pesky "Argument 'der' in 'useDerivation(der)' should not change between renders." --- packages/r3f/src/main/editable.tsx | 3 +++ .../shared/src/utils/uniqueKeyForAnyObject.ts | 16 ++++++++++++++++ .../src/panels/DetailPanel/DetailPanel.tsx | 1 + .../src/panels/DetailPanel/ObjectDetails.tsx | 8 +++++--- .../DopeSheet/Left/SheetRow.tsx | 8 +++++++- 5 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 theatre/shared/src/utils/uniqueKeyForAnyObject.ts diff --git a/packages/r3f/src/main/editable.tsx b/packages/r3f/src/main/editable.tsx index bb8e9ba..1581ed7 100644 --- a/packages/r3f/src/main/editable.tsx +++ b/packages/r3f/src/main/editable.tsx @@ -40,6 +40,9 @@ const createEditable = ( ) } + // TODO: detect if `editable()` is being called in the body of a react component, which is a common + // mistake. If it is, throw an error. + return forwardRef( ( { diff --git a/theatre/shared/src/utils/uniqueKeyForAnyObject.ts b/theatre/shared/src/utils/uniqueKeyForAnyObject.ts new file mode 100644 index 0000000..67a552c --- /dev/null +++ b/theatre/shared/src/utils/uniqueKeyForAnyObject.ts @@ -0,0 +1,16 @@ +const cache = new WeakMap() +let nextKey = 0 + +/** + * This function returns a unique string key for any JS object. This is useful for key-ing react components + * based on the identity of an object. + * + * @param obj - any JS object + * @returns a unique string key for the object + */ +export default function uniqueKeyForAnyObject(obj: object): string { + if (!cache.has(obj)) { + cache.set(obj, (nextKey++).toString()) + } + return cache.get(obj)! +} diff --git a/theatre/studio/src/panels/DetailPanel/DetailPanel.tsx b/theatre/studio/src/panels/DetailPanel/DetailPanel.tsx index f20d20d..603f81b 100644 --- a/theatre/studio/src/panels/DetailPanel/DetailPanel.tsx +++ b/theatre/studio/src/panels/DetailPanel/DetailPanel.tsx @@ -118,6 +118,7 @@ const DetailPanel: React.FC<{}> = (props) => { const selection = getOutlineSelection() const obj = selection.find(isSheetObject) + if (obj) { return ( = ({objects}) => { const obj = objects[0] - const key = useMemo(() => JSON.stringify(obj.address), [obj]) const config = useVal(obj.template.configPointer) return ( } propConfig={config} diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Left/SheetRow.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Left/SheetRow.tsx index 6be3adc..581bad7 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Left/SheetRow.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Left/SheetRow.tsx @@ -4,6 +4,7 @@ import React from 'react' import LeftSheetObjectRow from './SheetObjectRow' import AnyCompositeRow from './AnyCompositeRow' import {setCollapsedSheetItem} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/setCollapsedSheetObjectOrCompoundProp' +import uniqueKeyForAnyObject from '@theatre/shared/utils/uniqueKeyForAnyObject' const SheetRow: React.VFC<{ leaf: SequenceEditorTree_Sheet @@ -23,7 +24,12 @@ const SheetRow: React.VFC<{ > {leaf.children.map((sheetObjectLeaf) => ( ))}