I've created a React ponent which takes any ponent and renders it as a Pop-up. A parent ponent receives the ponent to be rendered (popped up). The rendered ponent is here the child ponent which using react-sizeme to get its size and pass back to parent ponent. The parent ponent must take the dimensions of child ponent, so adjusts' its height and width. This is the code:
class Popup extends React.Component<IPopupProps,IComponent>{
constructor(props:IPopupProps){
super(props);
this.state={
childComponent:this.props.children,
style:{
height:0,
width:0
}
}
}
// This function runs two times, before and after rendering child ponent
// & so have an improper visualization as the size is changed twice here
public OnSize = (size:any) =>{
const width = size.width +20;
const height =size.height+20;
this.setState({
style:{height,
width }
})
}
public render(){
return(
<div className='popup'>
<div style={this.state.style} className='popup-content'>
<a className="close" onClick={this.props.onExit}>
×
</a>
<this.state.childComponent onSize={this.OnSize}/>
</div>
</div>
)
}
}
I've created a React ponent which takes any ponent and renders it as a Pop-up. A parent ponent receives the ponent to be rendered (popped up). The rendered ponent is here the child ponent which using react-sizeme to get its size and pass back to parent ponent. The parent ponent must take the dimensions of child ponent, so adjusts' its height and width. This is the code:
class Popup extends React.Component<IPopupProps,IComponent>{
constructor(props:IPopupProps){
super(props);
this.state={
childComponent:this.props.children,
style:{
height:0,
width:0
}
}
}
// This function runs two times, before and after rendering child ponent
// & so have an improper visualization as the size is changed twice here
public OnSize = (size:any) =>{
const width = size.width +20;
const height =size.height+20;
this.setState({
style:{height,
width }
})
}
public render(){
return(
<div className='popup'>
<div style={this.state.style} className='popup-content'>
<a className="close" onClick={this.props.onExit}>
×
</a>
<this.state.childComponent onSize={this.OnSize}/>
</div>
</div>
)
}
}
The initial width and height is set to 0. So it doesn't renders properly. So is there any way so that to hide the child ponent or avoid its rendering before parent ponent gets the size?
EDIT: We can't get the size until the child ponent is rendered. So is there any trick to get this done. Just a ponent needs to be popped-up properly.
EDIT 2: Here's the PropsBuilder.tsx which calls the Popup.tsx and sends the ponent to display as children
class PopupBuilder extends React.Component<IPopupBuilderProps, IPopup>{
constructor(props:IPopupBuilderProps){
super(props);
this.state = {
showPopup:false
}
}
public togglePopup = () =>{
this.setState({
showPopup:!this.state.showPopup
})
}
public render (){
return(
<React.Fragment>
<button onClick={this.togglePopup}>{this.props.trigger}</button>
<React.Fragment>
{this.state.showPopup?<Popup onExit={this.togglePopup} >{this.props.ponent}</Popup>:null}
</React.Fragment>
</React.Fragment>
)
}
}
export default PopupBuilder;
Share
Improve this question
edited Nov 26, 2018 at 18:55
Nikhil Patil
asked Nov 26, 2018 at 14:59
Nikhil PatilNikhil Patil
931 gold badge3 silver badges8 bronze badges
5
- 1 shouldComponentupdate hook is there for such case – Bhojendra Rauniyar Commented Nov 26, 2018 at 15:02
- I was searching about this in the mean time. Actually we can't get the size of a ponent until it is rendered. We can't use shouldComponentUpdate I guess as it will be not rendered at all. So issue is now how to properly display any ponent as a pop-up. – Nikhil Patil Commented Nov 26, 2018 at 15:59
- Just render it offscreen (i.e. outside the viewport) at first, get the measurements, then render it onscreen. – Jared Smith Commented Nov 26, 2018 at 21:01
- @JaredSmith This suggestion worked actually. I biled it with Shevchenko answer – Nikhil Patil Commented Nov 27, 2018 at 10:00
- @NikhilPatil it's similar to an old, old trick in game dev. Since you only have such a small frame budget for games (16 ms) you typically "draw" the next frame to an image buffer in memory (fast and cheap) and then swap the whole thing all at once for what's on screen instead of drawing every object in the scene incrementally (slow/expensive). – Jared Smith Commented Nov 27, 2018 at 12:38
1 Answer
Reset to default 3Actually, this looks like more general DOM/JavaScript question.
Consider such case:
const span = document.createElement('span');
span.innerText = 'hello';
span.getBoundingClientRect() // -> { width: 0, height: 0, top: 0, … }
This is an indicator that you don't know the dimensions of the element until it is in DOM (Rendered in react);
document.body.appendChild(span);
span.getBoundingClientRect(); // -> {width: 50, height: 16, …}
My remendation to you in this case are:
- Child ponent should accept a property (function) from Parent one
- Use React "ref" feature to find actual dimensions of Child element
- Call the function in 'ponentDidMount' (use ponentDidUpdate if child can change dynamically), passing it child ponent dimensions.
If you don't have access to child ponent. You may wrap it like this:
// Popup.tsx
class Popup .... {
...
render() {
<Measurer>{this.props.children}</Measurer>
}
}
and implement the logic of fetching dimensions in it. Measurer is a direct child of Popup and their munication can be controlled by you.