Skip to content
This repository was archived by the owner on Aug 21, 2024. It is now read-only.

Commit 6dc7bcc

Browse files
speiggHexaField
andauthored
Optimize Query Reactors (#7908)
* Optimize Query Reactors A lot of low hanging fruit for React.memo() here. Significantly faster reactor updates, engine-wide. * fix bug with * fix bug with DropShadowReactor * destructure react impots --------- Co-authored-by: HexaField <joshfield999@gmail.com>
1 parent 51ba5aa commit 6dc7bcc

File tree

5 files changed

+44
-39
lines changed

5 files changed

+44
-39
lines changed

packages/client-core/src/user/components/Panel3D/useRender3DPanelSystem.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export function useRender3DPanelSystem(panel: React.MutableRefObject<HTMLDivElem
9292

9393
return () => {
9494
disableSystem(AvatarSelectRenderSystem)
95-
SystemDefinitions.delete(AvatarSelectRenderSystem)
95+
// todo - do we need to remove the system defintion?
9696
removeEntity(state.entity.value)
9797
window.removeEventListener('resize', resize)
9898
}

packages/engine/src/ecs/functions/SystemFunctions.tsx

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import React, { Suspense, useEffect } from 'react'
1+
/** Functions to provide system level functionalities. */
2+
3+
import React, { Component, ErrorInfo, FC, memo, Suspense, useEffect, useMemo } from 'react'
24

35
import { OpaqueType } from '@etherealengine/common/src/interfaces/OpaqueType'
46
import multiLogger from '@etherealengine/common/src/logger'
57
import { ReactorProps, ReactorRoot, startReactor } from '@etherealengine/hyperflux'
68

79
import { nowMilliseconds } from '../../common/functions/nowMilliseconds'
810
import { Engine } from '../classes/Engine'
11+
import { Entity } from '../classes/Entity'
912
import { QueryComponents, useQuery } from './ComponentFunctions'
1013
import { EntityReactorProps } from './EntityFunctions'
1114

@@ -15,7 +18,7 @@ export type SystemUUID = OpaqueType<'SystemUUID'> & string
1518
export interface System {
1619
uuid: SystemUUID
1720
execute: () => void // runs after preSystems, and before subSystems
18-
reactor: React.FC<ReactorProps>
21+
reactor: FC<ReactorProps>
1922
preSystems: SystemUUID[]
2023
subSystems: SystemUUID[]
2124
postSystems: SystemUUID[]
@@ -282,37 +285,46 @@ export const disableSystem = (systemUUID: SystemUUID) => {
282285
}
283286
}
284287

285-
function QueryReactor(props: {
286-
root: ReactorRoot
287-
query: QueryComponents
288-
ChildEntityReactor: React.FC<EntityReactorProps>
289-
}) {
290-
const entities = useQuery(props.query)
291-
return (
292-
<>
293-
{entities.map((entity) => (
294-
<QueryReactorErrorBoundary key={entity}>
288+
const QueryReactor = memo(
289+
(props: { root: ReactorRoot; entity: Entity; ChildEntityReactor: FC<EntityReactorProps> }) => {
290+
const entityRoot = useMemo(() => {
291+
return {
292+
...props.root,
293+
entity: props.entity
294+
}
295+
}, [props.root, props.entity])
296+
return (
297+
<>
298+
<QueryReactorErrorBoundary>
295299
<Suspense fallback={null}>
296-
<props.ChildEntityReactor root={{ ...props.root, entity }} />
300+
<props.ChildEntityReactor root={entityRoot} />
297301
</Suspense>
298302
</QueryReactorErrorBoundary>
299-
))}
300-
</>
301-
)
302-
}
303+
</>
304+
)
305+
}
306+
)
303307

304-
export const createQueryReactor = (Components: QueryComponents, ChildEntityReactor: React.FC<EntityReactorProps>) => {
308+
export const createQueryReactor = (Components: QueryComponents, ChildEntityReactor: FC<EntityReactorProps>) => {
305309
if (!ChildEntityReactor.name) Object.defineProperty(ChildEntityReactor, 'name', { value: 'ChildEntityReactor' })
310+
const MemoChildEntityReactor = memo(ChildEntityReactor)
306311
return function HyperfluxQueryReactor({ root }: ReactorProps) {
307-
return <QueryReactor query={Components} ChildEntityReactor={ChildEntityReactor} root={root} />
312+
const entities = useQuery(Components)
313+
return (
314+
<>
315+
{entities.map((entity) => (
316+
<QueryReactor root={root} key={entity} entity={entity} ChildEntityReactor={MemoChildEntityReactor} />
317+
))}
318+
</>
319+
)
308320
}
309321
}
310322

311323
interface ErrorState {
312324
error: Error | null
313325
}
314326

315-
class QueryReactorErrorBoundary extends React.Component<any, ErrorState> {
327+
class QueryReactorErrorBoundary extends Component<any, ErrorState> {
316328
public state: ErrorState = {
317329
error: null
318330
}
@@ -322,7 +334,7 @@ class QueryReactorErrorBoundary extends React.Component<any, ErrorState> {
322334
return { error }
323335
}
324336

325-
public componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
337+
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
326338
console.error('Uncaught error:', error, errorInfo)
327339
}
328340

packages/engine/src/scene/components/GroupComponent.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react'
1+
import React, { FC, memo } from 'react'
22
import { Camera, Material, Mesh, Object3D } from 'three'
33

44
import { none } from '@etherealengine/hyperflux'
@@ -99,18 +99,17 @@ export type GroupReactorProps = {
9999
obj: Object3DWithEntity
100100
}
101101

102-
export const createGroupQueryReactor = (
103-
GroupChildReactor: React.FC<GroupReactorProps>,
104-
Components: QueryComponents = []
105-
) =>
106-
createQueryReactor([GroupComponent, ...Components], function GroupQueryReactor(props) {
102+
export const createGroupQueryReactor = (GroupChildReactor: FC<GroupReactorProps>, Components: QueryComponents = []) => {
103+
const MemoGroupChildReactor = memo(GroupChildReactor)
104+
return createQueryReactor([GroupComponent, ...Components], function GroupQueryReactor(props) {
107105
const entity = props.root.entity
108106
const groupComponent = useComponent(entity, GroupComponent)
109107
return (
110108
<>
111109
{groupComponent.value.map((obj, i) => (
112-
<GroupChildReactor key={obj.uuid} entity={entity} obj={obj} />
110+
<MemoGroupChildReactor key={obj.uuid} entity={entity} obj={obj} />
113111
))}
114112
</>
115113
)
116114
})
115+
}

packages/engine/src/scene/systems/ShadowSystem.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,6 @@ const DropShadowReactor = createQueryReactor([ShadowComponent], function DropSha
181181
const shadowMaterial = useHookstate(shadowState)
182182
const groupComponent = useOptionalComponent(entity, GroupComponent)
183183
const shadow = useComponent(entity, ShadowComponent)
184-
const hasDropShadow = useOptionalComponent(entity, DropShadowComponent)
185184

186185
useEffect(() => {
187186
if (
@@ -191,7 +190,7 @@ const DropShadowReactor = createQueryReactor([ShadowComponent], function DropSha
191190
useShadows ||
192191
!groupComponent ||
193192
groupComponent.value.length === 0 ||
194-
hasDropShadow?.value
193+
hasComponent(entity, DropShadowComponent)
195194
)
196195
return
197196

packages/engine/src/xr/XRScenePlacementShaderSystem.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,12 @@ const ScenePlacementReactor = createGroupQueryReactor(
6363
const useShader = xrState.sessionActive.value && xrState.scenePlacementMode.value === 'placing'
6464
if (useShader) {
6565
obj.traverse(addShaderToObject)
66-
} else {
67-
obj.traverse(removeShaderFromObject)
66+
return () => {
67+
obj.traverse(removeShaderFromObject)
68+
}
6869
}
6970
}, [scenePlacementMode, sessionActive])
7071

71-
useEffect(() => {
72-
return () => {
73-
obj.traverse(removeShaderFromObject)
74-
}
75-
}, [])
76-
7772
return null
7873
},
7974
[VisibleComponent]

0 commit comments

Comments
 (0)