React safe way to mutate memoized resources
Author: krispyaCreated Sep 5, 2026Updated Sep 5, 2026
It was always a violation React's rules to mutate values returned by useMemo and useState but we did it anyways.
// Before: mutating an object stored in React state
const material = useMemo(() => new THREE.MeshStandardMaterial(), []);
useFrame(() => {
material.opacity = 0.5;
});
return <primitive object={material} attach="material" />;But now the React compiler actually errors this out. In React's model, a ref is the actual mutable concept.
const material = useMemo(() => new THREE.MeshStandardMaterial(), []);
const materialRef = useRef<THREE.MeshStandardMaterial>(null);
useFrame(() => {
if (materialRef.current) {
materialRef.current.opacity = 0.5;
}
});
return (
<primitive
object={material}
ref={materialRef}
attach="material"
/>
);Here is a more thorough discussion: https://github.com/reactwg/react-compiler/discussions/14
Following their lead, a React safe way of creating mutable resources would look something like this where there is an explicit setter. We can use setters to mutate, but we cannot use assignment!
const material = useResource(() => {
const value = new MeshStandardMaterial({ transparent: true });
return {
value,
cleanup: () => value.dispose()
};
});
useFrame(() => {
material.set(m => m.opacity = 0.5)
});
return <primitive object={material.value} attach="material" />;Source: pmndrs/react-three-fiber