Fix: Re-render the panels when object identity change

This fixes the pesky "Argument 'der' in 'useDerivation(der)' should not change between renders."
This commit is contained in:
Aria Minaei 2022-12-31 22:54:24 +01:00
parent 4596c2233c
commit c58bc694ee
5 changed files with 32 additions and 4 deletions

View file

@ -40,6 +40,9 @@ const createEditable = <Keys extends keyof JSX.IntrinsicElements>(
) )
} }
// 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( return forwardRef(
( (
{ {

View file

@ -0,0 +1,16 @@
const cache = new WeakMap<object, string>()
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)!
}

View file

@ -118,6 +118,7 @@ const DetailPanel: React.FC<{}> = (props) => {
const selection = getOutlineSelection() const selection = getOutlineSelection()
const obj = selection.find(isSheetObject) const obj = selection.find(isSheetObject)
if (obj) { if (obj) {
return ( return (
<Container <Container

View file

@ -1,21 +1,23 @@
import React, {useMemo} from 'react' import React from 'react'
import type SheetObject from '@theatre/core/sheetObjects/SheetObject' import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
import type {Pointer} from '@theatre/dataverse' import type {Pointer} from '@theatre/dataverse'
import type {$FixMe} from '@theatre/shared/utils/types' import type {$FixMe} from '@theatre/shared/utils/types'
import DeterminePropEditorForDetail from './DeterminePropEditorForDetail' import DeterminePropEditorForDetail from './DeterminePropEditorForDetail'
import {useVal} from '@theatre/react' import {useVal} from '@theatre/react'
import uniqueKeyForAnyObject from '@theatre/shared/utils/uniqueKeyForAnyObject'
const ObjectDetails: React.FC<{ const ObjectDetails: React.FC<{
/** TODO: add support for multiple objects (it would show their common props) */ /** TODO: add support for multiple objects (it would show their common props) */
objects: [SheetObject] objects: [SheetObject]
}> = ({objects}) => { }> = ({objects}) => {
const obj = objects[0] const obj = objects[0]
const key = useMemo(() => JSON.stringify(obj.address), [obj])
const config = useVal(obj.template.configPointer) const config = useVal(obj.template.configPointer)
return ( return (
<DeterminePropEditorForDetail <DeterminePropEditorForDetail
key={key} // we don't use the object's address as the key because if a user calls `sheet.detachObject(key)` and later
// calls `sheet.object(key)` with the same key, we want to re-render the object details panel.
key={uniqueKeyForAnyObject(obj)}
obj={obj} obj={obj}
pointerToProp={obj.propsP as Pointer<$FixMe>} pointerToProp={obj.propsP as Pointer<$FixMe>}
propConfig={config} propConfig={config}

View file

@ -4,6 +4,7 @@ import React from 'react'
import LeftSheetObjectRow from './SheetObjectRow' import LeftSheetObjectRow from './SheetObjectRow'
import AnyCompositeRow from './AnyCompositeRow' import AnyCompositeRow from './AnyCompositeRow'
import {setCollapsedSheetItem} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/setCollapsedSheetObjectOrCompoundProp' import {setCollapsedSheetItem} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/setCollapsedSheetObjectOrCompoundProp'
import uniqueKeyForAnyObject from '@theatre/shared/utils/uniqueKeyForAnyObject'
const SheetRow: React.VFC<{ const SheetRow: React.VFC<{
leaf: SequenceEditorTree_Sheet leaf: SequenceEditorTree_Sheet
@ -23,7 +24,12 @@ const SheetRow: React.VFC<{
> >
{leaf.children.map((sheetObjectLeaf) => ( {leaf.children.map((sheetObjectLeaf) => (
<LeftSheetObjectRow <LeftSheetObjectRow
key={'sheetObject-' + sheetObjectLeaf.sheetObject.address.objectKey} key={
'sheetObject-' +
// we don't use the object's address as the key because if a user calls `sheet.detachObject(key)` and later
// calls `sheet.object(key)` with the same key, we want to re-render this row.
uniqueKeyForAnyObject(sheetObjectLeaf.sheetObject)
}
leaf={sheetObjectLeaf} leaf={sheetObjectLeaf}
/> />
))} ))}