I am trying to get visual attributes (width to be precise) of a component once it's rendered and CSS is applied. I've been trying with componentDidMount but width is still 0, I am not sure what I'm doing wrong.
output:
rendering
component did mount. The ribbon's width is 0
And after that, if I click on my header's button to "re-route" back to the same page (i.e. trigger an update), then the componentDidUpdate is called with the proper width. Am I missing something or is this a bug?
Thanks you lots folks.
import React, {Component} from 'react';
export default class RibbonHeader extends Component {
componentDidMount() {
console.log('component did mount. The ribbon\'s width is', this.refs.ribbonSvg.width.animVal.value); // is 0
this.paintInSVG();
}
shouldComponentUpdate() {
console.log('should component update'); // never called
return true;
}
componentDidUpdate() {
// Not automatically called, but if I generate a routing event, it updates
console.log('component did update. The ribbon\'s width is', this.refs.ribbonSvg.width.animVal.value); // width is 1020px (good)
this.paintInSVG();
}
paintInSVG() {
const refRibbon = this.refs.ribbonSvg;
doSomeSVGMagicThatDependsOnTheWidth(refRibbon);
}
render() {
console.log('rendering');
return (
<svg ref="ribbonSvg" styles={{width: '100%'}}></svg>
);
}
}
EDIT:
Adding a timeout to componentDidMount does the job, although this is probably not normal
componentDidMount() {
setTimeout(() => {
this.paintInSVG();
}, 100);
}
Hmm...
¯_(ツ)_/¯
Try:
console.log('component did mount. The ribbon\'s width is', this.refs.ribbonSvg.offsetWidth);
Slightly better, but still not what I'm looking for.
(before and after timeout)
component did mount. The ribbon's width is 300
component did mount. The ribbon's width is 1000
Hmm. I get 300 both times, even when I check a full second later (http://jsfiddle.net/r94vwoxr/).
Honestly, I'm not an SVG expert, but this looks like a usage question. React is responsible for creating the DOM/SVG nodes before calling componentDidMount, but everything I'm seeing here seems to indicate React has done that correctly. Beyond that, it's up to the browser.
To me, this looks like a usage question, rather than a bug in the React core. Usage questions are better answered on sites like StackOverflow, as we try to use github issues for tracking bugs in the React core, and I don't see anything here to indicate that React isn't doing it's job. I suspect some kind of race condition, where the SVG nodes are created but the browser is still doing SVG layout or something. Perhaps there is a command to force SVG to flush, or perhaps it's a bug in chrome, or something. If you are able to come up with a clear example/jsfiddle that demonstrates a bug in the React core, let me know and we can re-investigate. Otherwise, I'd recommend asking on StackOverflow.
cc @sebmarkbage for ideas.
I am having the same problem. I am trying to get the width of a drop-down menu in order to put it below a header. The width is base on email's length but inside componenDidMount I am getting a slightly different width.
I could use setTimeout but I don't feel comfortable doing that.
Here is the code: https://codesandbox.io/s/jnpzn15vxw