I'm trying to figure out how to populate/render a ponent when the data is ready? Essentially I have a script that queries my server which returns data, then I parse it and make it into an collection with the properties I need. Then in another file, I have the react ponent that's looking for that object but they're running at the same time so the object doesn't exist when the ponent is looking for it.
I'm not sure how to proceed.
This is my ponent:
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'));
How I'm getting my data:
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()
})
I'm trying to figure out how to populate/render a ponent when the data is ready? Essentially I have a script that queries my server which returns data, then I parse it and make it into an collection with the properties I need. Then in another file, I have the react ponent that's looking for that object but they're running at the same time so the object doesn't exist when the ponent is looking for it.
I'm not sure how to proceed.
This is my ponent:
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'));
How I'm getting my data:
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()
})
Share
Improve this question
asked Jul 19, 2016 at 14:43
BatmanBatman
6,38322 gold badges88 silver badges161 bronze badges
5
- Have you looked into Redux at all? That's the easiest way to keep track of state and work with data – erichardson30 Commented Jul 19, 2016 at 14:49
- I haven't really, I just started looking at React today so I'm not too familiar with everything yet. – Batman Commented Jul 19, 2016 at 14:54
-
After you are ready with data, just use
setState
. Should be as simple as that. Don't do into Redux. It isn't really needed for beginners. And as React always mentions, render should be a function ofprops
(external) +state
(internal). – nyumerics Commented Jul 19, 2016 at 15:15 - I would have a parent ponent that uses sets the data to a variable on state, then pass that down as a prop to the child ponent – Luke Schunk Commented Jul 19, 2016 at 15:35
-
@activatedgeek I'm having a hard time seeing how
this.setState
works with my ponent. Is it a global variable? Ishome.get()
suppose to change the state when it's pleted? – Batman Commented Jul 19, 2016 at 18:55
6 Answers
Reset to default 3A mon way to do this in React is to keep track of when data is being fetched. This can be done e.g. by having a isFetching
field in your state:
// This would be your default state
this.state = {
isFetching: false
};
Then, when you fire off the request (preferably in ponentDidMount) you set isFetching
to true using:
this.setState({ isFetching: true });
And finally, when the data arrives, you set it to false again:
this.setState({ isFetching: false });
Now, in your render function you can do something like this:
render () {
return (
<div className="something">
<h3>Some content</h3>
{this.state.isFetching ? <LoadingComponent /> : (
<ul>
{listItems}
</ul>
)}
</div>
)
}
By using state, you don't have to worry about telling your ponent to do something, instead it reacts to changes in the state and renders it accordingly.
Update:
If you plan on actually using React, I'd suggest you change your approach into what I've described above (read more in the React docs). That is, move the code you have in your get
function into your React ponent's ponentDidMount
function. If that's not possible, you can probably just wait to call
ReactDOM.render(
<SliderTabs items={home.data.slider} />,
document.getElementById('slider-tabs')
);
until your data has arrived.
Here is the explaination of React's way of doing these type of things, tl;dr - render the ponent immediately and either display loading indicator until the data is ready or return null
from the render
method.
Put that data loading in parent ponent that updates the props of your ponent as the data is being loaded.
Use default props instead of default state, since you are not using state at all in your example. Replace the 'getInitialState' with this:
getDefaultProps: function() {
return {
items: []
};
}
You should test the length of the data collection. If the collection is empty, return a placeholder (a loading wheel for exemple). In other cases, you can display the data collection as usual.
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')
)
I have use the functional way to define a React Component as it's the remended way while you don't need of a state, refs or lifecycle methodes.
If you want to use this in a ES6 classe or with React.createCompnent (shoud be avoid), just use the function as the render function. (don't forget to extract items
form the props)
EDIT : By reading the new answers, I've realised that I haven't fully answered.
If you want the view to be updated when the data are loaded, You have to integrate a little more your data fetching code. A basic pattern in React is to separate your ponents in tow type : the Containers Component and the Presentational Component.
The Containers will only take care of the logic and to fetch the useful data. In the other hand, the Presentational Components will only display the data given by the Container.
Here a little example : (try it on jsfidle)
Test utilities
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)
)
Container Component
//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 : [] }
}
ponentDidMount() {
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} />
)
}
}
Presentational Component
//The Presenational Component. It's called List because, in fact, you can reuse this ponent 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>
)
}
Rendering the App
//Mount the Container Component. It doesn't need any props while he is handling his state itself
ReactDOM.render(
<SliderTabList />,
document.getElementById('slider-tabs')
)
Rather than checking for the length to not being 0, you also can initialise items
to null
in the state, to be able to differentiate fetching data from empty data. An other mon way os to put a flag (a boolean in fetchingData
int the state) to know if a data is fetching or not. But, in lots of articles, it's generaly reended to have a state as litle as possible and then calculate all you need from it. So here, I sugest you to check for the length or the null
.
I got a few answers but I was still having a lot of trouble understanding how to acplish what I was asking for. I understand that I should be retrieving the data with the ponents but I currently don't know enough about React to do that. I obviously need to spend more time learning it but for now I went with this:
Essentially, I added the property ready
to my home object:
home.ready: false,
home.init: function() {
// check if lists exist
home.check()
.then(home.get)
.then(function() {
home.ready = true;
})
}
Then I used ponentDidMount
and a setTimeout
to check when the data is ready and set the results to the this.state
let SliderTabs = React.createClass({
getInitialState: function() {
return {items:[]}
},
ponentDidMount: 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'));
Probably not the React way but it seems to work.
Ordinarily, you would arrange a response to an OnLoad
event, which will "fire" once the data has been loaded.
I agree with Emrys that your code should also be prepared to test whether the data is available yet, and to "do something reasonable" on the initial draw (when it probably isn't). But no, you would not then "poll" to see if the data has arrived: instead, you arrange to be notified when the event fires. At that time, you would (for example) re-draw the UI ponents to reflect the information.
I kindly refer you to the React documentation to see exactly how this notification is done ...
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744259332a4565552.html
评论列表(0条)