【问题标题】:Controlling Order of React Component Rendering控制 React 组件渲染的顺序
【发布时间】:2016-08-17 03:53:34
【问题描述】:

如您所知,React 组件是并行渲染的。无法保证它们完成渲染的顺序。

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

  1. InterviewContentMain (因为它会渲染标题

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

  2. InterviewContainer(应仅在 InterviewContentMain 渲染后渲染)
  3. TableOfContents(应仅在 InterviewContainer 和 InterviewContentMain 渲染后渲染)

这里有更多上下文https://youtu.be/OrEq5X9O4bw

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

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>
        )
    }
})

更新:

这是我尝试过的。虽然它们都 3 渲染,但我仍然有时间 TableOfContents 在 InterviewContentMain 或 InterviewContent 之前渲染,这意味着渲染后的 TableOfContent 重叠 &lt;p className="section-heading bold font-22" id="interview-heading"&gt;Interview&lt;/p&gt; 而不是在它下面渲染,因为我试图在 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>
        )
    }
})

【问题讨论】:

  • 当然可以控制渲染的顺序。 { someProp &amp;&amp; &lt;Component /&gt; }
  • 这就像一个if 声明...只有在someProp 为真时才渲染Component
  • @azium 的意思是你可以有条件地渲染一个组件,因此你可以控制何时渲染一个组件(在someProp 转换为true 之后)

标签: javascript reactjs


【解决方案1】:

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

你说:

TableOfContents(应仅在 InterviewContainer 和 InterviewContentMain 渲染后渲染)

.. 所以在TableOfContents 父容器的render 方法中,检查某些值是否为真,就像在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>
    )
}

【讨论】:

  • 所以...我已经更仔细地阅读了您的问题和 cmets,我认为这里的问题归结为:“我怎样才能将道具发送给父母”。答案是......将回调函数传递给调用它的孩子,例如componentDidMount。其中特别说:嘿,父母!我渲染了!
  • 在设置之前不会{this.state.rendered && 被评估!?
  • 不,我不想将道具发送给父母。我希望父母在完成后通知孩子,以便孩子在它之后渲染。查看我更新的代码..我的第二次尝试
  • 这是视觉上的问题。 TableOfContents 应该始终在标题

    之后呈现,因为我正在应用一个 JS 粘性并告诉它始终呈现在 interview-header 部分下方。好吧,这个视频显示,有时它仍然在渲染之前,因此与采访标题 youtube.com/watch?v=9dIRR32HkH8

    重叠
  • 感谢最后一个视频我明白你现在在说什么了。想...我的预感是 Ink.UI.Sticky 有点奇怪,而不是默认情况下对我来说似乎很可预测的“渲染顺序”
【解决方案2】:

您在componentDidMount 中呼叫setState。打电话给componentWillMount。在componentDidMount 中立即调用setState 是一种反模式,因为componentDidMount 是调用render 的那个,请参阅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>
      );
    }

【讨论】:

  • 好的,但是您没有将 secondRendered 作为道具传递给 TableOfContents。 TableOfContents 怎么知道 this.state.secondRendered 是什么?您不想将其作为 InterviewContent 的道具传递吗?
  • 也不会 {this.state.secondRendered && );本身就够了吗? TableOfContents 在 secondRendered 之后根本不会渲染,不知道为什么我需要在我的 TableOfContents 中进行任何检查
  • 我的代码正在运行,它似乎按照我想要的顺序呈现......所以我觉得我很好。谢谢
  • 您不需要将其作为道具传递。看一下: {this.state.secondRendered && } 这会在上一次渲染完成之前阻止下一次渲染。请接受它对你有用的答案:)
  • 那么它怎么知道那是什么?这代表内容表。通过this,状态在组件内部。
猜你喜欢
  • 1970-01-01
  • 2020-11-30
  • 2021-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
  • 1970-01-01
相关资源
最近更新 更多