WTF WTF - 3 months ago 13
React JSX Question

Check Whether Another Component Has Rendered Before calling JS

First watch this, so you can see the behavior going on.

Timing Issue (JS in one component relies on another component to exist first)

I need to be able to somehow check that another component exists before I apply this JS in this component's ComponentDidMount

const TableOfContents = Component({
store: Store('/companies'),
componentDidMount() {
const el = ReactDOM.findDOMNode(this);
console.log("table of contents mounted");
if(document.getElementById('interview-heading') && el) {

new Ink.UI.Sticky(el, {topElement: "#interview-heading", bottomElement: "#footer"});
}
},


it does hit my if statement and does hit the Sticky() function but I still think I have problems when I refresh the page whereas this JS isn't working on the interview-heading component for some reason.

Note the
id="interview-heading"
below.

const InterviewContent = Component({
componentDidMount() {
console.log("InterviewContent mounted");
},
render(){
var company = this.props.company;

return (
<div id="ft-interview-content">
<p className="section-heading bold font-22" id="interview-heading">Interview</p>
<InterviewContentMain company={company}/>
</div>
)
}
})

const InterviewContentMain = Component({
componentDidMount() {
console.log("InterviewContentMain mounted");
},
render(){
var company = this.props.company;

return (
<div id="interview-content" className="clear-both">
<div className="column-group">
<div className="all-20">
<TableOfContents company={company}/>
</div>
<div className="all-80">
<InterviewContainer company={company}/>
</div>
</div>
</div>
)
}
})



export default InterviewContent;


I realize TableOfContents is being rendered before InterviewContent because it's a child of TableOfContents and I believe in React children are rendered before their parents (inside-out)?

Answer

I think you need to rethink your component structure. I don't know your entire setup, but it looks like you should probably have a shared parent component pass the message from TableOfContents to InterviewContent:

const InterviewContentMain = Component({
    getInitialState() {
        return {
            inkEnabled: false
        }
    },
    componentDidMount() {
        console.log("InterviewContentMain mounted");
    },
    enableInk() {
        this.setState({ inkEnabled: true });
    }
    render(){
        var company = this.props.company;

        return (
            <div id="interview-content" className="clear-both">
                <div className="column-group">
                    <div className="all-20">
                        <TableOfContents inkEnabled={this.state.inkEnabled} company={company}/>
                    </div>
                    <div className="all-80">
                        <InterviewContainer enableInk={this.enableInk} company={company}/>
                    </div>
                </div>
            </div>
        )
    }
})

const TableOfContents = Component({
   store: Store('/companies'),
   componentDidMount() {
      console.log("table of contents mounted");
      this.props.enableInk();
   },
   ...

const InterviewContent = Component({
    enableInk() {
        new Ink.UI.Sticky(el, {topElement: "#interview-heading", bottomElement: "#footer"});
    },
    // willReceiveProps isn't called on first mount, inkEnabled could be true so 
    componentDidMount() {
        if (this.props.inkEnabled) {
            this.enableInk();
        }
    },
    componentWillReceiveProps(nextProps) {
        if (this.props.inkEnabled === false && nextProps.inkEnabled === true) {
            this.enableInk();
        }
    }
    render(){
        var company = this.props.company;

        return (
            <div id="ft-interview-content">
                <p className="section-heading bold font-22" id="interview-heading">Interview</p>
                <InterviewContentMain company={company}/>
            </div>
        )
    }
})

Then have componentDidMount trigger this.props.enableInk().

Or better yet, why not just put the Ink.UI.Sticky call in componentDidMount of InterviewContent?

Comments