在决定渲染之前反应等待映射函数以防止div闪存

Dee*_*pak 2 javascript dictionary reactjs

我有一点麻烦阻止div闪存,其中反应将呈现错误消息,然后接收道具,最后渲染道具.

在我的EventsView组件中,我有以下内容.

view.js

var view;
if (_.size(this.props.events) !== 0) {
view =  this.props.events.map(function(year) {
                return <YearView year={year} />;
        });
} else {
    view = <NoEventsView />
}
Run Code Online (Sandbox Code Playgroud)

所以变量view被渲染,最初没有this.props.events页面加载,因为我有另一部分文件创建它.创建this.props.events时,将呈现事件.这是通过react.Backbonemixin 完成的.

我尝试过使用一些组件生命周期方法,比如componentWillUpdate.问题是他们似乎不希望以我希望它们工作的方式工作,并且永远不会呈现错误消息.我在下面尝试过的例子(以及其他)

我想做这样的事情.

view.js

componentWillUpdate: function(nextprops, nextstate) {
if (_.size(nextprops.events) !== 0) {
    var view =  nextprops.events.map(function(year) {
                    return <YearView year={year} />;
            });
    this.setState({
        view: view
    });
} else {
    this.setState({
        view: <NoEventsView />
    })
}
},

// render this.state.view
Run Code Online (Sandbox Code Playgroud)

然后我会设置getInitialState:viewthis.props.events地图.

*编辑 - 一个临时和可怕的解决方法*

所以我遇到的问题是我有一个接受单个道具的顶级组件,这是一个像这样的全局变量

view.js

React.render(<EventsView events={theseEvents} />, document.getElementById('mainContent'));
Run Code Online (Sandbox Code Playgroud)

theseEvents 实际上是在另一个文件中初始化的Backbone Collection全局变量.

在文档加载时theseEvents将无法填充,因此我的视图将<NoEventView />随之闪烁,然后在theseEvents填充时重新渲染.这由下面显示的主干mixin处理.

丹的解决方案指出了我正确的方向.我将全局变量设置window.hasEvents为true或false,具体取决于我从ajax请求中返回的内容,但到那时React已经渲染(组件将启动,hasEvents如果它完成hasEvents可能是假的).即使我做hasEvents<EventsView />反应的支柱也不会在它改变时重新渲染.

因此,作为临时解决方法,我默认hasEvents为真实并呈现EventsView.然后我等待组件加载并检查它是否与hasEvents同步.如下所示.老实说,这种解决方法并不是很愉快.

view.js

ar EventsView = React.createBackboneClass({
mixins: [
    React.BackboneMixin("events", "all")
],

getInitialState: function() {
    return {
        hasEvents: window.hasEvents
    }
},

componentDidMount: function() {
    var model = this;
    // This waits after component loading to check whether hasEvents is the same
    setTimeout(function() {
        if(!(model.state.hasEvents == window.hasEvents)) {
            model.setState({
                hasEvents: window.hasEvents
            })
        };
    }, 1000);
},

render: function() {
    var view;
    if (this.props.events.length > 0) {
        view =  this.props.events.map(function(year) {
                        return <YearView year={year} />;
                });
    }
    if (!this.state.hasEvents)  {
        view = <NoEventsView />
    }
    return {
        // other parts of the page were also rendered here
        {view}
    }
});
Run Code Online (Sandbox Code Playgroud)

componentDidMount在组件安装后基本上等待一段时间,然后双重检查全局变量.绝对不是一个很好的解决方法,特别是因为它依赖于1秒的theseEvents人口,它只适用于初始组件安装.

Dan*_*mov 5

你的第二种方法不是"React方式"(虽然从技术上说它可能有效),因为你不应该把React元素置于状态.只有数据应该去那里,render如果需要弄清楚数据如何与DOM结构相对应.state除非绝对必要,否则最好避免.

话虽如此,我不太清楚你想要实现的目标.假设您希望在事件发生之前阻止"无事件"闪存,则组件可以执行此操作的唯一方法是知道正在获取数据.如果,除了eventsprop,你传递isLoadingboolean prop,你可以这样做:

render: function () {
  var isEmpty = this.props.events.length === 0;
  if (isEmpty) {
    return this.props.isLoading ?
      <p>Loading...</p> : // note you can also return null here to render nothing
      <NoEventsView />;
  }

  return this.props.events.map(function (year) {
    return <YearView year={year} />;
  });    
}
Run Code Online (Sandbox Code Playgroud)

  • 您可以修改Backbone模型以使用`isFetching()`方法.否则我不确定你的问题究竟是什么,你可以在[JSBin](http://jsbin.com)上重现它,所以我可以看看吗? (2认同)