Closed Djordjenp closed 2 years ago
Great question.
I'd probably do it first this way:
const positionTooltip2 = (arc, tooltip) =>
IO.of( arc.dataset.centroid.split(',') )
.chain(centroid =>
addStyleIO(['left', `calc(50% + ${centroid[0] }px)`], tooltip)
.chain(() => addStyleIO(['top', `calc(50% + ${centroid[1] }px)`], tooltip))
.chain(() => addStyleIO(['transform', 'translate(-50%, -50%)'], tooltip))
)
That works fine and doesn't rely on actually forcibly executing the inner IO. But it does still nest IOs, which is mildly distasteful. So instead I might consider doing this:
const addStyleIO = ( /* add this param ---> */ centroid, [prop, val], element) =>
IO(() => {
element.style[prop] = val;
return centroid; // <----------- also insert this line
})
const positionTooltip2 = (arc, tooltip) =>
IO.of( arc.dataset.centroid.split(',') )
.chain(centroid => addStyleIO(centroid, ['left', `calc(50% + ${centroid[0] }px)`], tooltip))
.chain(centroid => addStyleIO(centroid, ['top', `calc(50% + ${centroid[1] }px)`], tooltip))
.chain(centroid => addStyleIO(centroid, ['transform', 'translate(-50%, -50%)'], tooltip))
)
That is a little intrusive/awkward to modify the definition of addStyleIO
to forcibly continue the centroid
context from chain(..)
call to chain(..)
call. It does work, though, and is an effective and not uncommon way of approaching things.
TBH, I think this situation is a decent justification for the "do-style" syntax over the "chain-style" syntax:
const positionTooltip2 = (arc, tooltip) => IO.do(function*(){
var centroid = arc.dataset.centroid.split(',');
yield addStyleIO(['left', `calc(50% + ${centroid[0] }px)`], tooltip);
yield addStyleIO(['top', `calc(50% + ${centroid[1] }px)`], tooltip);
yield addStyleIO(['transform', 'translate(-50%, -50%)'], tooltip);
})
If you can get over the function*
and the yield
overhead, I think this style is much cleaner and more readable for the task at hand. It creates a single scope for the multiple addStyleIO
s to share (to access centroid
), but everything is nicely flattened into a single IO (under the covers), so there's a clean un-nested vertical orientation to the IO operations.
Thank you for answer Kyle, yeah I definitely see the advantage of using the generator form in this example.
Hi Kyle, I was wondering does it make sense to be calling another IO monad inside of another like this