问题
I'm using react and react-bootstrap. I want to know whether there's a better, cleaner, more idiomatic approach than what I've come up with.
The Problem
I want to position a popover callout that points to a button on my page that provides a hint for where the user should start their workflow. The user can subsequently dismiss this popover. It took me a long time to figure out this hack-y approach to measure the elements' dimensions and positions to properly position the callout:
The target of the callout:
<Button
bsClass="button"
className="button-blue"
id="connectParentsButton"
onClick={( event ) => { this.handleOpenInviteParents( event );}}
ref={( input ) => { this.connectParentsButtonRef = input; }}
>
+ Connect Parents
</Button>
The idea is to use ref
to store the target as a property of the parent React component, and then access it from the sibling callout component to perform the measurements.
The callout component:
<RightBottomHintBox
isShow={this.state.isShowConnectParentsHint && !this.state.isDismissHideConnectParentsHint}
target={this.connectParentsButtonRef}
id="connectParentsHint"
onHide={this.handleHideConnectParentsHint}
/>
In my RightBottomHintBox
component, I have to
- use
document.getElementById()
to get dimenions and positions - use guards to avoid trying to access nodes that don't exist yet
- store dimensions and coordinates in class properties rather than component state
And I have to do this in the the callout's render()
to ensure that my callout component gets mounted even if it's not displayed, so that the DOM node exists and can be correctly measured.
let myStyle = this.props.isShow ? {} : { visibility: 'hidden' };
Failed approaches
computing dimensions when the callout's
componentDidMount()
fires. The DOM nodes of either the callout or the target are often not yet therecomputing dimensions when the parent component's
componentDidMount()
fires. The same problem exists, you can't be sure that the DOM nodes exist at this point.
The above two approaches led me to this thread: When exactly is `componentDidMount` fired?
One post suggests that to be sure that all DOM nodes are ready, you'd have to go up to the top component. I don't like this approach because it would break encapsulation and separation of concerns.
Another thread, How can I respond to the width of an auto-sized DOM element in React?, suggests using the react-measure library to do measurements, which might work, but for my particular case, I wanted to avoid having another library to manage because this app is small.
Background context
I'm creating a page that allows the user to input a list of students' parents' email addresses. The initial page lists students and parents' email addresses that have already been input. However, the first time the user comes to this page, there may be a list of students, with no parent email addresses. I want to provide a hint to the user that they should click on 'Connect Parents' button to open up a wizard to guide the user in data input.
回答1:
I have another failed attempt here that may spur someone to the correct solution.
export function getSize(cpt) {
var elem = document.getElementById("ruler");
const html = ReactDOMServer.renderToStaticMarkup(cpt);
elem.innerHTML = html;
return [elem.scrollWidth, elem.scrollHeight];
}
var Foo = React.createClass({
componentDidMount() {
const sz = this.elem.getBoundingClientRect();
ReactDOM.render(<span>{ [sz.width,sz.height].join("x") }</span>,
document.getElementById('actual'));
},
render() {
return <div ref={e => { this.elem = e; }} className="content">
<p> Bar!! BAZ </p> <p> another line </p> </div>;
}
})
Setting up getSize to render into any div (onscreen or off) gives about 76x84, while the actual size reported by componentDidMount (and confirmed by dev tools) is 188x52.
来源:https://stackoverflow.com/questions/40939133/how-do-you-reliably-measure-react-components-for-computed-position-of-popovers-a