控制反应组件渲染的顺序

时间:2016-08-17 03:53:34

标签: javascript reactjs

如您所知,React组件并行渲染。无法保证他们完成渲染。

我想按照这个确切的顺序呈现以下组件:

  1. InterviewContentMain (因为它会呈现标题

    。我需要首先渲染此标题,以便我可以在渲染后在其他两个组件中对其进行操作。我将运行一些关于它的JS等,稍后将从其他两个组件的componentDidMount开始,这就是为什么我希望首先渲染它的原因)

  2. InterviewContainer (只应在InterviewContentMain呈现后呈现)
  3. TableOfContents (只应在InterviewContainer和InterviewContentMain呈现后呈现)
  4. 这是一个更多的背景https://youtu.be/OrEq5X9O4bw

    我尝试了很多东西,你可以看到生命周期方法,这可能是完全错误的,或者甚至不确定人们甚至在这种情况下做了什么,但到目前为止还没有运气。 / p>

    const Main = Component({
        getInitialState() {
            console.log("getInitialState being called");
            return null;
        },
        renderMe() {
            console.log("changed InterviewContent's state");
            this.setState({renderInk: true});
        },
        componentDidMount() {
            console.log("InterviewContentMain 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>
                    <InterviewContent renderMe={this.renderMe} company={company}/>
                </div>
            )
        }
    })
    
    export default InterviewContentMain;
    
    
    const InterviewContent = Component({
        componentDidMount() {
            console.log("InterviewContent mounted");
        },
        renderMe() {
            console.log("changed InterviewContent's state");
            this.setState({subParentRendered: true});
        },
        render(){
            var company = this.props.company;
    
            return (
                <div id="interview-content" className="clear-both">
                    <div className="column-group">
                        <div className="all-20">
                            <TableOfContents renderHeader={this.props.renderMe}  renderContent={this.renderMe} company={company}/>
                        </div>
                        <div className="all-80">
                            <InterviewContainer company={company}/>
                        </div>
                    </div>
                </div>
            )
        }
    })
    
    const TableOfContents = Component({
        enableInk() {
            new Ink.UI.Sticky(el, {topElement: "#interview-heading", bottomElement: "#footer"});
        },
        componentDidMount() {
            console.log("table of contents mounted");
            this.renderHeader;
            this.renderContent;
            enableInk(); // I only want to run this if the Header and the Content have rendered first
        },
        render(){
            return (
                <div>
                    <p className="margin-8"><span className="blue medium"><Link to="/">HOME</Link></span></p>
            )
        }
    })
    

    更新:

    这是我尝试过的。虽然它们全部渲染,但我仍然得到TableOfContents在InterviewContentMain或InterviewContent之前呈现的时间,这意味着渲染后的TableOfContent重叠<p className="section-heading bold font-22" id="interview-heading">Interview</p>而不是由于我试图在TableOfContents中应用的粘性JS而在其下面渲染

    const InterviewContentMain = Component({
        getInitialState() {
            console.log("getInitialState being called");
            return {rendered: false};
        },
        componentDidMount() {
            console.log("InterviewContentMain mounted")
            this.setState({rendered: true});
        },
        render(){
            var company = this.props.company;
    
            return (
                <div id="ft-interview-content">
                    <div className="section-heading bold font-22" id="interview-heading">Interview</div>
                    { this.state.rendered && <InterviewContent company={company}/> }
                </div>
            )
        }
    })
    
    export default InterviewContentMain;
    
    
    const InterviewContent = Component({
        getInitialState() {
            console.log("getInitialState being called");
            return {rendered: false};
        },
        componentDidMount() {
            console.log("InterviewContent mounted")
            this.setState({rendered: true});
        },
        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>
            )
        }
    })
    
    const TableOfContents = Component({
        componentDidMount() {
            const el = ReactDOM.findDOMNode(this);
            new Ink.UI.Sticky(el,{topElement: "#interview-heading", bottomElement: "#footer"});
            console.log("TableOfContents mounted");
        },
        render(){
            return (
                <div>
                    <p className="margin-8"><span className="blue medium"><Link to="/">HOME</Link></span></p>
                </div>
            )
        }
    })
    

2 个答案:

答案 0 :(得分:3)

如果要有条件地渲染组件,请将其包装在条件(无论是函数还是内联布尔表达式)中

你说:

  

TableOfContents(只应在InterviewContainer和InterviewContentMain渲染后呈现)

..所以在render父容器的TableOfContents方法中,检查某些值是否为真,就像在if语句中一样。

render(){
    var company = this.props.company;

    return (
        <div id="interview-content" className="clear-both">
            <div className="column-group">
                <div className="all-20">
                  {this.state.subParentRendered &&
                    <TableOfContents renderHeader={this.props.renderMe}  renderContent={this.renderMe} company={company}/>
                  }
                </div>
                <div className="all-80">
                    <InterviewContainer company={company}/>
                </div>
            </div>
        </div>
    )
}

答案 1 :(得分:0)

您正在setState中呼叫componentDidMount。在componentWillMount中调用它。立即在setState中调用componentDidMount是一种反模式,因为componentDidMount是调用render的{​​{1}},请参阅this discussion

我使用了稍微不同的语法,但应该清楚可以理解。

class InterviewContentMain ...
    this.state = {
      firstRendered: false
    }

    componentWillMount() {
      this.setState({ firstRendered: true });
    }

    render() {
      return (
      {this.state.firstRendered && 
       <InterviewContent />
      }
      );
    }

class InterviewContent ...
    this.state = {
      second: false
    }

    componentWillMount() {
      this.setState({ secondRendered: true });
    }

    render() {
      return (
      {this.state.secondRendered && 
       <TableOfContents />
      }
      );
    }

class TableOfContents ...

    render() {
      return (
       <div>Hello World in order</div>
      );
    }