Fix the recursion issue with theatric

This commit is contained in:
Aria Minaei 2023-01-24 18:45:41 +01:00
parent 97ab020bfb
commit 00bb2d3310
2 changed files with 33 additions and 9 deletions

View file

@ -1,4 +1,4 @@
import {button, initialize, useControls} from 'theatric' import {button, initialize, types, useControls} from 'theatric'
import {render} from 'react-dom' import {render} from 'react-dom'
import React, {useState} from 'react' import React, {useState} from 'react'
import state from './state.json' import state from './state.json'
@ -32,11 +32,12 @@ function App() {
baz: button(() => console.log($get((p) => p.bar))), baz: button(() => console.log($get((p) => p.bar))),
}) })
const {another, panel, yo} = useControls( const {another, panel, col, yo} = useControls(
{ {
another: '', another: '',
panel: '', panel: '',
yo: 0, yo: types.number(0),
col: types.rgba(),
}, },
{panel: 'My panel'}, {panel: 'My panel'},
) )
@ -54,7 +55,7 @@ function App() {
justifyContent: 'center', justifyContent: 'center',
}} }}
> >
<div>{JSON.stringify(bar)}</div> {/* <div>{JSON.stringify(bar)}</div> */}
<SomeComponent id="first" /> <SomeComponent id="first" />
<SomeComponent id="second" /> <SomeComponent id="second" />
<button <button
@ -73,6 +74,7 @@ function App() {
</button> </button>
{showComponent && <SomeComponent id="hidden" />} {showComponent && <SomeComponent id="hidden" />}
{yo} {yo}
{JSON.stringify(col)}
</div> </div>
) )
} }

View file

@ -8,6 +8,7 @@ import {getProject} from '@theatre/core'
import type {Pointer} from '@theatre/dataverse' import type {Pointer} from '@theatre/dataverse'
import {isPointer} from '@theatre/dataverse' import {isPointer} from '@theatre/dataverse'
import studio from '@theatre/studio' import studio from '@theatre/studio'
import isEqualWith from 'lodash-es/isEqualWith'
import isEqual from 'lodash-es/isEqual' import isEqual from 'lodash-es/isEqual'
import {useEffect, useMemo, useState, useRef} from 'react' import {useEffect, useMemo, useState, useRef} from 'react'
@ -33,6 +34,17 @@ const maybeTransaction =
let _projectConfig: IProjectConfig['state'] | undefined = undefined let _projectConfig: IProjectConfig['state'] | undefined = undefined
// used for comparing config objects, to avoid re-rendering when the config object is recreated
// but the values are the same except for functions
function equalityCheckWithFunctionsAlwaysEqual(
a: unknown,
b: unknown,
): boolean | undefined {
if (typeof a === 'function' && typeof b === 'function') {
return true
}
}
export function initialize(config: IProjectConfig) { export function initialize(config: IProjectConfig) {
if (_projectConfig !== undefined) { if (_projectConfig !== undefined) {
console.warn( console.warn(
@ -100,12 +112,20 @@ export function useControls<Config extends ControlsAndButtons>(
*/ */
const configRef = useRef(config) const configRef = useRef(config)
const _config = useMemo(() => { const _config = useMemo(() => {
if (isEqual(config, configRef.current)) { let currentConfig = configRef.current
return configRef.current
} else { if (
!isEqualWith(
config,
configRef.current,
equalityCheckWithFunctionsAlwaysEqual,
)
) {
configRef.current = config configRef.current = config
return config currentConfig = config
} }
return currentConfig
}, [config]) }, [config])
const {folder} = options const {folder} = options
@ -142,7 +162,9 @@ export function useControls<Config extends ControlsAndButtons>(
Object.entries(buttons).map(([key, value]) => [ Object.entries(buttons).map(([key, value]) => [
`${folder ? `${folder}: ` : ''}${key}`, `${folder ? `${folder}: ` : ''}${key}`,
() => { () => {
value.onClick() // the value of the button is a function, so we can't use it as a dependency, but we can use it as a ref
// @ts-ignore
configRef.current[key].onClick?.()
}, },
]), ]),
), ),