How to reduce undefined judgments

Hey everyone, in this example, because I need to clear the resources occupied by the engine when the component is uninstalled, I defined the engine outside onMount. Since the initialization of the engine requires canvasRef, it is undefined at the beginning. This means that if I need to modify the properties of engine(), I need to check whether it is undefined multiple times. How should I improve it?
No description
11 Replies
Maciek50322
Maciek503222mo ago
You can do something like that with <Show> https://playground.solidjs.com/anonymous/759ff1d4-b587-4a1c-b14f-375556f39642 when you pass the function to <Show>'s children, you get the argument of accessor to truthy when value
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
AlexErrant
AlexErrant2mo ago
...is this real code? Why aren't you calling engine on line 10? I polish some of my code in this commit here by doing a few not null assertions. I know they're not null because I know information that Typescript doesn't know; namely I know Solid's lifecycle methods https://github.com/AlexErrant/Pentive/commit/c38aadda78da89b592ea8dfa392ada3b3da8c50a in particular, I know that the JSX will be executed first, setting the Ref so I know it will no longer be null then onMount/creatEffect/onCleanup will run with the not-null element-ref not sure if I'm actually answering your question... but there was an attempt lol
KiaClouth
KiaClouthOP2mo ago
I should have made a mistake there, it was actually engine().dispose(); Thank you for your reply, I know using ! can solve the problem, but I am worried that it has hidden dangers, so I try to find a more elegant solution, but maybe I am asking for trouble // Thanks for your answer, but I think I described it wrong. Actually I want to solve the problem of ts, because I need to execute many statements like engine().scene = {}, but judging engine() !== undefined can't ensure that engine() !== undefined afterwards. That's it, I want to write less error handling without using !. I hope I made it clear...
AlexErrant
AlexErrant2mo ago
IMO you're looking for trouble. Typescript has limitations. Asserting not-null is ugly, but this is why I explained to you solid's lifecyle methods. Trying to strictly follow Typescript all the time when you know better is... literally trusting the tool over your own brain >_>
Maciek50322
Maciek503222mo ago
Well when you want to use the engine inside jsx, then Show can do it the way I used it above. Inside onMount and createEffect it's guaranteed that refs will not be nulls (if they are actually used / mounted).
Madaxen86
Madaxen862mo ago
@KiaClouth Getting back to your example, I would do:
onMount(()=>{
let eng = new BABYLON.Engine(canvasRef,true);
eng.loadingScreen = {}
setEngine(eng)
})
//Narrow in reactive contexts
//and what you can always do inside of effects (createEffect, createMemo,...) is e.g.
createEffect(()=>{
let engineRef = engine();
if (engineRef) {
//now TS picks up that engineRef !== undefined
}

})
//or you use the "?" e.g.
onCleanup(()=>{
engine()?.dispose()
})
//and what should also work is
function someEventHandler() {
setEngine(prev => {
if (prev) {
prev.loadingScreen = {}
prev.scene = new Scene() //!?? or whatever
return scene
}
return prev
})
}
onMount(()=>{
let eng = new BABYLON.Engine(canvasRef,true);
eng.loadingScreen = {}
setEngine(eng)
})
//Narrow in reactive contexts
//and what you can always do inside of effects (createEffect, createMemo,...) is e.g.
createEffect(()=>{
let engineRef = engine();
if (engineRef) {
//now TS picks up that engineRef !== undefined
}

})
//or you use the "?" e.g.
onCleanup(()=>{
engine()?.dispose()
})
//and what should also work is
function someEventHandler() {
setEngine(prev => {
if (prev) {
prev.loadingScreen = {}
prev.scene = new Scene() //!?? or whatever
return scene
}
return prev
})
}
Maciek50322
Maciek503222mo ago
I mean in every context that executes after onMount (in which you set the engine) you are guarenteed to have not null engine(), so you can write engine()!.dispose() Also if you don't like the ! you can do
const e = engine();
if (e) {
e.scene = {}
}
const e = engine();
if (e) {
e.scene = {}
}
KiaClouth
KiaClouthOP2mo ago
Thanks, I hadn't thought of doing that at all, thanks for your advice OK, I'll try this.
Madaxen86
Madaxen862mo ago
Additionally, I don't think you need a signal to store the engine, because Babylons will take care of updating the canvas element which you passed to new Babylon. So this should work:
export function BabylonCanvas() {
let canvasRef!:HTMLCanvasElement
let engine!:BABYLON.Engine
onMount(()=>{
engine = new BABYLON.Engine(canvasRef,true);
engine.loadingScreen = {}
let scene = new BABYLON.Scene(engine);
//create scene ...
engine.renderLoop(() => {
scene.render();
})
})



return <canvas ref={canvasRef} />
}
export function BabylonCanvas() {
let canvasRef!:HTMLCanvasElement
let engine!:BABYLON.Engine
onMount(()=>{
engine = new BABYLON.Engine(canvasRef,true);
engine.loadingScreen = {}
let scene = new BABYLON.Scene(engine);
//create scene ...
engine.renderLoop(() => {
scene.render();
})
})



return <canvas ref={canvasRef} />
}
KiaClouth
KiaClouthOP2mo ago
When I need to store a value that may change in a component, I immediately think of signal. But from this example, it's really just a matter of storing it in an ordinary variable. Thanks
Madaxen86
Madaxen862mo ago
That’s usually true. In this case Babylon handles the updates (“reactivity”)
Want results from more Discord servers?
Add your server