I want something like this:
const App = () => {
let [bounds, setBounds] = createSignal()
let $piano
onMount(() => {
setBounds($piano.getBoundingClientRect())
let key_xys = createMemo(() => {
let _bounds = bounds()
if (!_bounds) { return [] }
// some calculation about bounds
return [_bounds.left, _bounds.right]
})
})
return (<PianoView ref={$piano} key_xys={key_xys}/>)
}
const PianoView = (props) => {
let { ref, key_xys } = props
return (<div class='p-wrap' ref={ref}>
<span style={transform: `translate(0, ${key_xys[0]})`}/>
</div>)
}
So I want to position a span that depends on it's bounds on the dom with some calculations.
Of course the above example doesn't work because key_xys
the calculated value doesn't exist at creation time.
CodePudding user response:
Two issues.
key_xys
value is an Accessor, basically a function to retrieve the value (which createMemo and createSignal returns), so in PianoView jsx, you must call it.
<span style={`transform: translate(0, ${key_xys()[0]}px)`}/>
Also in SolidJS, the style attribute can be a string like native html, which I decided to write as.
- As you noted, this application won't run because
key_xys
is not defined, because you declared it insideonMount
callback. There's no need to do this. Move thekey_xys
declaration in App component scope.
const App = () => {
let [bounds, setBounds] = createSignal();
let $piano;
let key_xys = createMemo(() => {
let _bounds = bounds() as any;
if (!_bounds) {
return [];
}
// some calculation about bounds
return [_bounds.left, _bounds.right];
});
onMount(() => {
setBounds($piano.getBoundingClientRect());
});
return <PianoView ref={$piano} key_xys={key_xys} />;
};
Code Answer
Full code answer below.
const App = () => {
let [bounds, setBounds] = createSignal();
let $piano;
let key_xys = createMemo(() => {
let _bounds = bounds() as any;
if (!_bounds) {
return [];
}
// some calculation about bounds
return [_bounds.left, _bounds.right];
});
onMount(() => {
setBounds($piano.getBoundingClientRect());
});
return <PianoView ref={$piano} key_xys={key_xys} />;
};
const PianoView = (props) => {
const {ref, key_xys} = props
return (
<div ref={ref}>
hiii
<span style={`transform: translate(0, ${key_xys()[0]}px)`} />
</div>
);
};
CodePudding user response:
I believe you can do this without a signal. Just make key_xys
derived state based on the ref. Also, make sure to call the accessor key_xys()
when passing it to the Piano
component. Finally, make sure not to destructure props since any reactive props will lose their reactivity.
const App = () => {
let $piano;
const key_xys = () => {
const bounds = $piano?.getBoundingClientRect();
if (!bounds) return [0, 0];
return [bounds.left, bounds.right];
};
return <PianoView ref={$piano} key_xys={key_xys()} />;
};
const PianoView = (props) => {
return (
<div ref={props.ref}>
<span style={{ transform: `translate(0, ${props.key_xys[0]})` }} />
</div>
);
};