@playcanvas/react
Version:
A React renderer for PlayCanvas – build interactive 3D applications using React's declarative paradigm.
77 lines • 2.87 kB
JavaScript
import { useEffect, useRef } from 'react';
import { useParent } from "./use-parent.js";
import { useApp } from "./use-app.js";
/**
* This hook is used to create a script component on an entity.
* @param scriptConstructor - The constructor for the script.
* @param props - The props for the script.
*
* @example
* const script = useScript(MyScript, {
* myProperty: 'value',
* });
*/
export const useScript = (scriptConstructor, props, ref) => {
const parent = useParent();
const app = useApp();
const scriptName = toLowerCamelCase(scriptConstructor.name);
const scriptRef = useRef(null);
const scriptComponentRef = useRef(null);
// Create the script synchronously
useEffect(() => {
if (!app)
return;
// Ensure the parent entity has a script component
if (!parent.script) {
parent.addComponent('script');
}
// Check if we've already created the script
if (!scriptRef.current) {
// Create the script instance with the provided attributes
const scriptComponent = parent.script;
const scriptInstance = scriptComponent.create(scriptConstructor, {
properties: { ...props },
preloading: false,
});
if (ref) {
if (typeof ref === 'function') {
ref(scriptInstance);
}
else {
ref.current = scriptInstance;
}
}
scriptRef.current = scriptInstance;
scriptComponentRef.current = scriptComponent;
}
// Cleanup function to remove the script when the component is unmounted
return () => {
const scriptComponent = scriptComponentRef.current;
const script = scriptRef.current;
scriptRef.current = null;
scriptComponentRef.current = null;
if (app && app.root && script && scriptComponent) {
scriptComponent.destroy(scriptName);
if (ref) {
if (typeof ref === 'function') {
ref(null);
}
else {
ref.current = null;
}
}
}
};
}, [app, parent, scriptConstructor]);
// Update script props when they change
useEffect(() => {
const script = scriptRef.current;
// Ensure componentRef.current exists before updating props
if (!script)
return;
const filteredProps = Object.fromEntries(Object.entries(props).filter(([key]) => key in script));
Object.assign(script, filteredProps);
}, [props]);
};
const toLowerCamelCase = (str) => str[0].toLowerCase() + str.substring(1);
//# sourceMappingURL=use-script.js.map