我正在试图弄清楚如何在数据准备好时填充/渲染组件?基本上我有一个查询我的服务器的脚本返回数据,然后我解析它并使其成为一个具有我需要的属性的集合。然后在另一个文件中,我有反应组件正在寻找该对象,但它们同时运行,因此当组件正在寻找它时该对象不存在。
我不知道该怎么办。
这是我的组成部分:
let SliderTabs = React.createClass({
getInitialState: function() {
return { items: [] }
},
render: function() {
let listItems = this.props.items.map(function(item) {
return (
<li key={item.title}>
<a href="#panel1">{item.title}</a>
</li>
);
});
return (
<div className="something">
<h3>Some content</h3>
<ul>
{listItems}
</ul>
</div>
);
}
});
ReactDOM.render(<SliderTabs items={home.data.slider} />,
document.getElementById('slider-tabs'));
我如何获取数据:
var home = home || {};
home = {
data: {
slider: [],
nav: []
},
get: function() {
var getListPromises = [];
$.each(home.lists, function(index, list) {
getListPromises[index] = $().SPServices.SPGetListItemsJson({
listName: home.lists[index].name,
CAMLViewFields: home.lists[index].view,
mappingOverrides: home.lists[index].mapping
})
getListPromises[index].list = home.lists[index].name;
})
$.when.apply($, getListPromises).done(function() {
home.notice('Retrieved items')
home.process(getListPromises);
})
},
process: function(promiseArr) {
var dfd = jQuery.Deferred();
$.map(promiseArr, function(promise) {
promise.then(function() {
var data = this.data;
var list = promise.list;
// IF navigation ELSE slider
if (list != home.lists[0].name) {
$.map(data, function(item) {
home.data.nav.push({
title: item.title,
section: item.section,
tab: item.tab,
url: item.url.split(",")[0],
path: item.path.split("#")[1].split("_")[0]
})
})
} else {
$.map(data, function(item) {
home.data.slider.push({
title: item.title,
url: item.url.split(",")[0],
path: item.path.split("#")[1]
})
})
}
})
})
console.log(JSON.stringify(home.data))
dfd.resolve();
return dfd.promise();
}
}
$(function() {
home.get()
})
答案 0 :(得分:1)
在React中执行此操作的常用方法是跟踪何时获取数据。这可以通过例如完成。通过在您的州内设置isFetching
字段:
// This would be your default state
this.state = {
isFetching: false
};
然后,当您触发请求时(最好在componentDidMount中),您可以使用以下命令将isFetching
设置为true:
this.setState({ isFetching: true });
最后,当数据到达时,再次将其设置为false:
this.setState({ isFetching: false });
现在,在渲染功能中,您可以执行以下操作:
render () {
return (
<div className="something">
<h3>Some content</h3>
{this.state.isFetching ? <LoadingComponent /> : (
<ul>
{listItems}
</ul>
)}
</div>
)
}
通过使用州,您不必担心告诉您的组件执行某些操作,而是对状态中的更改做出反应并相应地呈现它。
<强>更新强>
如果您计划实际使用React,我建议您将方法改为我上面所述(请参阅the React docs中的更多内容)。也就是说,将您在get
函数中的代码移动到React组件的componentDidMount
函数中。如果那不可能,您可以等待致电
ReactDOM.render(
<SliderTabs items={home.data.slider} />,
document.getElementById('slider-tabs')
);
直到您的数据到达。
答案 1 :(得分:0)
您应该测试数据收集的长度。如果集合为空,则返回占位符(例如加载轮)。在其他情况下,您可以照常显示数据集合。
const SliderTabs = ({items}) => {
let listItems = <p>Loading data...</p>
if(items.length != 0)
listItems = items.map(item =>
<li key={item.title}>
<a href="#panel1">{item.title}</a>
</li>
)
return (
<div className="something">
<h3>Some content</h3>
<ul>
{listItems}
</ul>
</div>
)
}
ReactDOM.render(
<SliderTabs items={home.data.slider} />,
document.getElementById('slider-tabs')
)
我已经使用功能方式来定义React组件,因为它是您不需要状态,参考或生命周期方法时的推荐方式。
如果你想在ES6 classe或React.createCompnent中使用它(应该避免),只需使用该函数作为渲染函数。 (别忘了从道具中提取items
)
编辑:通过阅读新的答案,我意识到我还没有完全回答。
如果要在加载数据时更新视图,则必须集成更多的数据获取代码。 React中的基本模式是将您的组件分为两种类型:容器组件和演示组件。
容器只会处理逻辑并获取有用的数据。另一方面,演示组件仅显示容器给出的数据。
这里有一个小例子:(try it on jsfidle)
测试实用程序
var items = [{title: "cats"},{title: "dogs"}]
//Test function faking a REST call by returning a Promise.
const fakeRest = () => new Promise((resolve, reject) =>
setTimeout(() => resolve(items), 2000)
)
容器组件
//The Container Component that will only fetch the data you want and then pass it to the more generic Presentational Component
class SliderTabList extends React.Component {
constructor(props) { //
super(props)
//You should always give an initial state (if you use one of course)
this.state = { items : [] }
}
componentDidMount() {
fakeRest().then(
items => this.setState({ items }) //Update the state. This will make react rerender the UI.
)
}
render() {
//Better to handle the fact that the data is fetching here.
//This let the Presentational Component more generic and reusable
const {items} = this.state
return (
items.length == 0
? <p>Loading Data...</p>
: <List items={items} />
)
}
}
演示文稿
//The Presenational Component. It's called List because, in fact, you can reuse this component with other Container Component. Here is power of React.
const List = ({items}) => {
//Prepare the rendering of all items
const listItems = items.map(item =>
<li key={item.title}>
<a href="#panel1">{item.title}</a>
</li>
)
//Simply render the list.
return (
<div className="something">
<h3>Some content</h3>
<ul>
{listItems}
</ul>
</div>
)
}
渲染应用
//Mount the Container Component. It doesn't need any props while he is handling his state itself
ReactDOM.render(
<SliderTabList />,
document.getElementById('slider-tabs')
)
您可以在状态中初始化items
到null
,而不是检查长度是否为0,以便能够区分从空数据中获取数据。另一种常见的方法是将一个标志(状态为fetchingData
中的布尔值)设置为知道数据是否正在获取。但是,在很多文章中,我们通常建议尽可能使用一个州,然后从中计算出你需要的所有东西。所以在这里,我要求您检查长度或null
。
答案 2 :(得分:0)
Here是React执行这些类型事务的方式的解释,tl; dr - 立即渲染组件并显示加载指示符直到数据准备好或从{{返回null
1}}方法。
答案 3 :(得分:0)
将数据加载到父组件中,以便在加载数据时更新组件的道具。
使用默认道具而不是默认状态,因为您的示例中根本没有使用状态。将'getInitialState'替换为:
getDefaultProps: function() {
return {
items: []
};
}
答案 4 :(得分:0)
我得到了一些答案,但我仍然很难理解如何完成我的要求。我知道我应该使用组件检索数据,但我目前还不了解React做到这一点。我显然需要花更多的时间来学习它,但是现在我接受了这个:
基本上,我将属性ready
添加到我的主对象:
home.ready: false,
home.init: function() {
// check if lists exist
home.check()
.then(home.get)
.then(function() {
home.ready = true;
})
}
然后我使用componentDidMount
和setTimeout
检查数据何时准备就绪,并将结果设置为this.state
let SliderTabs = React.createClass({
getInitialState: function() {
return {items:[]}
},
componentDidMount: function() {
let that = this;
function checkFlag() {
if(home.ready == false) {
window.setTimeout(checkFlag, 100); /* this checks the flag every 100 milliseconds*/
} else {
that.setState({items: home.data.slider})
}
}
checkFlag();
},
render: function() {
let listItems = this.state.items.map(function(item) {
return (
<li key={item.title}>
<a href="#panel1">{item.title}</a>
</li>
);
});
return (
<div className="something">
<h3>Some content</h3>
<ul>
{listItems}
</ul>
</div>
);
}
});
ReactDOM.render(<SliderTabs/>,
document.getElementById('slider-tabs'));
可能不是React的方式,但似乎有效。
答案 5 :(得分:-2)
通常情况下,您会安排对OnLoad
事件的回复,该事件将在数据加载后“触发”。
我同意Emrys的说法,你的代码也准备测试数据是否可用,并在初始绘制时“做一些合理的”(当它可能 isn'时吨)。但是,不会,您不会“轮询”以查看数据是否已到达:相反,您安排在事件触发时收到通知。那时,你会(例如)重新绘制 UI组件以反映信息。
我恳请您参考React文档,以确切了解此通知是如何完成的......