I have this span element. am fetching data and putting some text in that span element, therefore sometimes that span elements width is 200 px, sometimes its 100px. I want this span to have margin-right: half of its width. I am using this technique:
const [width, setWidth] = useState()
const ref = useRef(null)
useLayoutEffect(()=>{
setWidth(ref.current.offsetWidth);
},[])
<span className='big ' id='meria' ref={ref} style={{marginRight: width / 2 }}>sometext</span>
I want the width element to re-render on change of window.location.pathname, but I cant use that as dependency. any tips?
CodePudding user response:
Don't use a dependency array. The useEffect
would be called on each render, but if the offsetWidth
didn't change, setting the state won't have any effect:
useLayoutEffect(() => {
setWidth(ref.current.offsetWidth);
})
Since the change happens on each render, you can skip the state, and just calculate it directly from the ref
as suggested by kind user's comment:
<span className='big ' id='meria' ref={ref} style={{marginRight: ref.current.offsetWidth / 2 }}>sometext</span>
Note: margin
doesn't work on inline elements, you should change the display
CSS property inline-block
or block
.
Another option for this specific case is to set the margin using percentage in CSS, since according to MDN:
The size of the margin as a percentage, relative to the inline size (width in a horizontal language, defined by writing-mode) of the containing block.
CodePudding user response:
Do you use a seperate CSS-stylesheet? (even if you don't this still should work, because it's basically just CSS) - If yes you can easily do some CSS trickery to get the same effect without a single line of JS needed You would do that as follows:
Wrap the span (or whatever element you want to have the dynamic margin for) in a div - this div then gets the width: fit-content
- you can now set margin-right: 50%
on your span element. This is everything you need for your desired result (The 50% always are calculated from the parent ... and with fit-content the parent will be the childs width)
Since you are using spans
you'll need to add white-space: nowrap
to the span (otherwise the span wouldn't overflow out of the div and just linebreak, which is not what we want)
span {
margin-left: 50%;
width: fit-content;
white-space: nowrap;
border: solid
}
.container {
width: fit-content;
}
<div >
<span>short one</span>
</div>
<div >
<span>this one is longer</span>
</div>
<div >
<span>and this one is even longer than the one before</span>
</div>
I used margin-left for demonstartion purpouse (just change it tho whatever you need . the snippet is more to show what I meant, and show the dinamically changing maring based on width of the span)