0

I'm using a Modal based on the example code from the docs: https://react-bootstrap.github.io/components.html#modals-live. What I want is for a child component to be rendered only when 1) it's data is ready, and 2) when the modal is opened. Also, the child component needs to know how wide the area is it has to work with (because it's doing some d3.js svg drawing inside).

I'm also, btw, using fixed-data-table, so the data (a concept) is put in state and the Model is opened on row click:

onRowClick={(evt, idx, obj)=>{
  let concept = filteredDataList.getObjectAt(idx);
  this.openModal();
  this.setState({concept});
}}

As per the Modal docs example, the Modal sits there in the render and exists in the DOM in a closed state until something opens it. However, the Modal.Body doesn't seem to exist till the Modal is open. My bright idea is that the child, ConceptDetail, can get the ClientWidth from a ref to its containing div.

let conceptDetail = '';
if (this.state.concept) {
    conceptDetail = <ConceptDetail 
                        containerRefs={this.refs}
                        concept={concept} />/
}

<Modal>
   ...
  <Modal.Body>
    <div ref="modalBody" style={{width:'100%'}}>
        {conceptDetail}
    </div>
  </Modal.Body>
  ...
</Modal>

This would work, except the ref isn't ready until after the child component is rendered. To figure out what's going on, I did this:

componentWillUpdate(){
  if (this.refs.modalBody) {
    let { clientWidth } = this.refs.modalBody;
    alert(`will update, width: ${clientWidth}`);
  } else {
    alert('will update, no modalBody ref');
  }
}
componentDidUpdate(){
  if (this.refs.modalBody) {
    let { clientWidth } = this.refs.modalBody;
    alert(`did update, width: ${clientWidth}`);
  } else {
    alert('did update, no modalBody ref');
  }
}

When I click a row, I see the alert will update, no modalBody ref, followed by the alert did update, width: 868, and then the child component displays. But the child didn't get the width (or the updated ref) because it actually renders before the componentDidUpdate. The reason I see the alert first (I assume) is because the Modal is animated and doesn't appear instantly on rendering. When I close the Modal, I actually do see for a quick flash that it has finally received the correct width, but at that point I don't need it anymore.

So, most specifically, my question is: How can a child component of a Modal be informed of the modal body's width? I would be even more grateful if someone might explain the right way to do what I'm trying to do in general: Trigger display of a Modal with a child component that would like to receive data and container dimensions as props.

Sigfried
  • 2,943
  • 3
  • 31
  • 43

1 Answers1

0

Ok, so a partial answer that got me going is here: Trigger modal shown for React Bootstrap

So, onEntered doesn't fire till the modal is all ready, so that's the time to get the width:

<Modal ... 
    onEntered={(() => {
      let { clientWidth } = this.refs.modalBody;
      if (this.state.modalWidth !== clientWidth)
        this.setState({modalWidth:clientWidth});
    }).bind(this)}>
...
  <Modal.Body>
    <div ref="modalBody">
      {this.getConceptDetail()}
    </div>
  </Modal.Body>
...
</Modal>

Then a separate method to get the child component (if ready):

getConceptDetail() {
  const {concept, modalWidth} = this.state;
  if (concept && modalWidth) {
    let conceptId = concept.records[0].rollupConceptId;
    return <ConceptDetail 
              width={modalWidth}
              concept={concept} 
              conceptId={conceptId}/>;
  }
  return <h3>no concept detail</h3>;
}

This isn't terrible, I guess, and it works. If someone knows a better way to structure it, I'd be happy to hear.

ADDENDUM: Sort of works, that is. The child component that actually needs to know the width is a couple levels down from the Modal body, so it needs to know the width of its direct parent... grrr How are react components supposed to know their container directions??

Community
  • 1
  • 1
Sigfried
  • 2,943
  • 3
  • 31
  • 43