there should be no setState. suspense returns a result and that result becomes available immediately.
imo this:
reader.addEventListener("loadend", async (event) => {
is also a different concern, it has nothing to do with the model component and should not be mixed into it. the result of that process should be handed over to the model. i just realize stlloader.parse is sync, so you just need use memo
function App() {
const [data, set] = useState()
useEffect(() => {
let reader = new FileReader()
reader.addEventListener("loadend", async (event) => set(event.target.result))
...
}, [])
return data && <Model data={data} />
function Model({ data, ...props }) {
const geo = useMemo(() => new STLLoader().parse(data), [data])
return <mesh geometry={geo} {...props} />