dispose of transform controls on deselect
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { runInAction } from "mobx";
|
||||
import type { ObjectInstance, R3, Runtime } from "../types";
|
||||
import { useMemo, useRef, type RefObject } from "react";
|
||||
import { useMemo, useRef, useEffect, useCallback, type RefObject } from "react";
|
||||
import type { Group } from "three";
|
||||
import { Euler, Quaternion, Vector3 } from "three";
|
||||
import { TransformControls, useHelper } from "@react-three/drei";
|
||||
import { BoxHelper } from "three";
|
||||
import { Euler, Quaternion, Vector3, BoxHelper, type LineBasicMaterial } from "three";
|
||||
import { TransformControls } from "@react-three/drei";
|
||||
import { useThree, useFrame } from "@react-three/fiber";
|
||||
import { state } from "../state";
|
||||
import { nextObjectEditMode } from "../state/worldEditorState";
|
||||
import { ObjectViewInternal, type ObjectViewInternalHandle } from "./ObjectViewInternal";
|
||||
@@ -39,13 +39,44 @@ const SelectionOverlay = observer(function ({ objectId, ref, onTransformChange,
|
||||
[ref],
|
||||
);
|
||||
|
||||
useHelper(isSelected ? groupRef : { current: null }, BoxHelper, 'white');
|
||||
// BoxHelper — manually disposed because BoxHelper has no dispose() of its own
|
||||
const scene = useThree(s => s.scene);
|
||||
const helperRef = useRef<BoxHelper | null>(null);
|
||||
useEffect(() => {
|
||||
const target = groupRef.current;
|
||||
if (!isSelected || !target)
|
||||
return;
|
||||
const helper = new BoxHelper(target, 'white');
|
||||
scene.add(helper);
|
||||
helperRef.current = helper;
|
||||
return () => {
|
||||
scene.remove(helper);
|
||||
helper.geometry.dispose();
|
||||
(helper.material as LineBasicMaterial).dispose();
|
||||
helperRef.current = null;
|
||||
};
|
||||
}, [isSelected, groupRef, scene]);
|
||||
useFrame(() => helperRef.current?.update());
|
||||
|
||||
// TransformControls — drei never calls dispose() on unmount, leaking all gizmo
|
||||
// geometries. Callback ref ignores null so tcRef.current survives React's
|
||||
// ref-clear-on-unmount; effect cleanup then calls dispose() with the live instance.
|
||||
const tcRef = useRef<{ dispose(): void } | null>(null);
|
||||
const setTcRef = useCallback((tc: { dispose(): void } | null) => {
|
||||
if (tc !== null)
|
||||
tcRef.current = tc;
|
||||
}, []);
|
||||
useEffect(() => () => {
|
||||
tcRef.current?.dispose();
|
||||
tcRef.current = null;
|
||||
}, [isSelected]);
|
||||
|
||||
if (!isSelected || selectionMode === undefined || !groupRef.current)
|
||||
return null;
|
||||
|
||||
return (
|
||||
<TransformControls
|
||||
ref={setTcRef as never}
|
||||
object={groupRef as RefObject<Group>}
|
||||
mode={selectionMode}
|
||||
onChange={onTransformChange}
|
||||
|
||||
Reference in New Issue
Block a user