Memoize comopnents of deriver()

This commit is contained in:
Aria Minaei 2022-07-12 13:08:08 +02:00 committed by Aria
parent 558882ff0a
commit 86dd2cbf86

View file

@ -4,7 +4,6 @@ import {useDerivation} from '@theatre/react'
import type {$IntentionalAny} from '@theatre/shared/utils/types' import type {$IntentionalAny} from '@theatre/shared/utils/types'
import React, {useMemo, useRef} from 'react' import React, {useMemo, useRef} from 'react'
import {invariant} from './invariant' import {invariant} from './invariant'
import {emptyArray} from '@theatre/shared/utils'
type DeriveAll<T> = IDerivation< type DeriveAll<T> = IDerivation<
{ {
@ -36,23 +35,6 @@ function deriveAllD<T extends Record<string, $<any>> | $<any>[]>(
}) as $IntentionalAny }) as $IntentionalAny
} }
export function useReactPrism(
fn: () => React.ReactNode,
deps: readonly any[] = emptyArray,
): React.ReactElement {
const derivation = useMemo(() => prism(fn), deps)
return <DeriveElement der={derivation} />
}
export function reactPrism(fn: () => React.ReactNode): React.ReactElement {
return <DeriveElement der={prism(fn)} />
}
function DeriveElement(props: {der: IDerivation<React.ReactNode>}) {
const node = useDerivation(props.der)
return <>{node}</>
}
/** This is only used for type checking to make sure the APIs are used properly */ /** This is only used for type checking to make sure the APIs are used properly */
interface TSErrors<M> extends Error {} interface TSErrors<M> extends Error {}
@ -76,41 +58,47 @@ type ReactDeriver<Props extends {}> = (
export function deriver<Props extends {}>( export function deriver<Props extends {}>(
Component: React.ComponentType<Props>, Component: React.ComponentType<Props>,
): ReactDeriver<Props> { ): ReactDeriver<Props> {
return React.forwardRef(function deriverRender( const finalComp = React.memo(
props: Record<string, $IntentionalAny>, React.forwardRef(function deriverRender(
ref, props: Record<string, $IntentionalAny>,
) {
let observableArr = []
const observables: Record<string, IDerivation<$IntentionalAny>> = {}
const normalProps: Record<string, $IntentionalAny> = {
ref, ref,
} ) {
for (const key in props) { let observableArr = []
const value = props[key] const observables: Record<string, IDerivation<$IntentionalAny>> = {}
if (isDerivation(value)) { const normalProps: Record<string, $IntentionalAny> = {
observableArr.push(value) ref,
observables[key] = value }
} else { for (const key in props) {
normalProps[key] = value const value = props[key]
if (isDerivation(value)) {
observableArr.push(value)
observables[key] = value
} else {
normalProps[key] = value
}
} }
}
const initialCount = useRef(observableArr.length) const initialCount = useRef(observableArr.length)
invariant( invariant(
initialCount.current === observableArr.length, initialCount.current === observableArr.length,
`expect same number of observable props on every invocation of deriver wrapped component.`, `expect same number of observable props on every invocation of deriver wrapped component.`,
{initial: initialCount.current, count: observableArr.length}, {initial: initialCount.current, count: observableArr.length},
) )
const allD = useMemo(() => deriveAllD(observables), observableArr) const allD = useMemo(() => deriveAllD(observables), observableArr)
const observedPropState = useDerivation(allD) const observedPropState = useDerivation(allD)
return ( return (
observedPropState && observedPropState &&
React.createElement(Component, { React.createElement(Component, {
...normalProps, ...normalProps,
...observedPropState, ...observedPropState,
} as Props) } as Props)
) )
}) }),
)
finalComp.displayName = `deriver(${Component.displayName})`
return finalComp
} }