@playcanvas/react
Version:
A React renderer for PlayCanvas – build interactive 3D applications using React's declarative paradigm.
54 lines • 2.3 kB
JavaScript
import { useLayoutEffect, useMemo } from 'react';
import { StandardMaterial } from 'playcanvas';
import { useApp } from './use-app';
import { getColorPropertyNames, useColors } from '../utils/color';
import { validateAndSanitizeProps, createComponentDefinition } from '../utils/validation';
/**
* This hook is used to create a material instance and update its properties when the props change.
* @param {Materialrops} props - The props to pass to the material.
* @returns {StandardMaterial} material - The material instance.
* @see https://api.playcanvas.com/engine/classes/StandardMaterial.html
*
* @example
* const material = useMaterial({
* diffuse: 'red',
* opacity: 0.5,
* });
*
* // use the material
* <Render type="box" material={material} />
*/
export const useMaterial = (props) => {
const app = useApp();
const safeProps = validateAndSanitizeProps(props, componentDefinition);
// Get color props with proper type checking
const colorProps = useColors(props, colors);
const propsWithColors = { ...safeProps, ...colorProps };
// Create the material instance only once when 'app' changes
const material = useMemo(() => new StandardMaterial(), [app]);
// Update material properties when 'props' change
useLayoutEffect(() => {
if (material) {
// Filter the props to only include those in the standard material
const filteredProps = Object.fromEntries(Object.entries(propsWithColors).filter(([key]) => key in material));
Object.assign(material, filteredProps);
material.update();
}
}, [app, material, propsWithColors]);
// Clean up the material when the component unmounts
useLayoutEffect(() => {
return () => {
if (material) {
material.destroy();
}
};
}, [material]);
return material;
};
// dynamically build a list of property names that are colors
const tmpMaterial = new StandardMaterial();
const colors = getColorPropertyNames(tmpMaterial);
tmpMaterial.destroy();
// create a schema for the material props
const componentDefinition = createComponentDefinition("Material", () => new StandardMaterial(), (material) => material.destroy(), "StandardMaterial");
//# sourceMappingURL=use-material.js.map