我在防止div闪存方面遇到了一些麻烦,其中react将呈现错误消息,然后接收道具并最终呈现道具。
在我的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 />
}
因此呈现变量view
,最初页面加载时没有this.props.events
,因为我有另一部分文件创建它。创建this.props.events时,将呈现事件。这是通过react.Backbone
mixin完成的。
我尝试过使用某些组件生命周期方法,例如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
然后我会将getInitialState:view
设置为this.props.events
地图。
*编辑 - 一种暂时的,可怕的解决方法*
所以我遇到的问题是我有一个接受单个道具的顶级组件,这是一个像这样的全局变量
view.js
React.render(<EventsView events={theseEvents} />, document.getElementById('mainContent'));
theseEvents
实际上是在另一个文件中初始化的Backbone Collection全局变量。
文档加载theseEvents
将无法填充,因此我的视图会随<NoEventView />
一起闪烁,然后在填充theseEvents
时重新渲染。这由下面显示的主干mixin处理。
window.hasEvents
设置为true或false,具体取决于我从ajax请求中返回的内容,但到那时React已经呈现(该组件将以hasEvents
开始时为真,当时它已完成hasEvents
可能是错误的)。即使我hasEvents
<EventsView />
支持hasEvents
反应也不会在它发生变化时重新渲染。
因此,作为临时解决方法,我将EventsView
默认为true并呈现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}
}
});
。然后我等待组件加载并检查它是否与hasEvents同步。如下所示。老实说,这种解决方法并不是很愉快。
view.js
componentDidMount
基本上theseEvents
在组件安装后等待一段时间,然后双重检查全局变量。绝对不是一个很好的解决方法,特别是因为它依赖于1秒的{{1}}人口而且它只适用于初始组件安装。
答案 0 :(得分:5)
你的第二种方法不是“React方式”(虽然技术上可能有效),因为你不应该把React元素置于状态。只有数据应该去那里,如果需要弄清楚数据如何与DOM结构相对应,则在render
。除非绝对必要,否则最好避免使用state
。
话虽如此,我不太确定你想要实现的目标。假设您希望在事件发生之前阻止“无事件”闪存,则组件可以执行此操作的唯一方法是知道正在获取数据。除了events
道具之外,如果你传递isLoading
布尔道具,你可以这样做:
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} />;
});
}
答案 1 :(得分:3)
由于我在我的应用程序开始检查用户是否经过身份验证时发出请求,这就是我在我的组件中处理它的方式。父组件状态链接到我的商店,它作为属性向下传递authenticated
。
我最初将组件hasUpdated
状态设置为false,因为它将从父级接收道具我等到componentWillRecieveProps
被触发,然后将hasUpdated
设置为true
这意味着我们的电话已经恢复。然后它呈现它需要的元素。
不确定这是否是最好的方法,但到目前为止它已经满足了我们的需求。
var SomeComponent= React.createClass({
displayName: 'SomeComponent',
getInitialState: function() {
return {
hasUpdated : false
};
},
getDefaultProps: function() {
return {
authenticated : false
};
},
componentWillReceiveProps: function(nextProps) {
this.setState({ hasUpdated : true });
},
render: function() {
var AuthElement;
if(this.state.hasUpdated){
if(this.props.authenticated){
AuthElement= <div>Authenticated</div>;
}else{
AuthElement= <div>Not Authenticated</div>;
}
}
return (
{AuthElement}
);
}
});