Quickstart
A quick dive into getting started with Lore
A quick dive into getting started with Lore
In this step we'll create the Load More button that we'll need for infinite scrolling.
You can view the finished code for this step by checking out the
infinite-scrolling.1
branch of the completed project.
The first component we're going to create will be the LoadMoreButton
. The user will click this button to load more tweets, and it will have three responsibilities:
Let's start by expanding the metadata for a collection to know whether there is a "next page" of data to load.
To do that, take a look at the API response for any endpoint that returns a collection:
{
data: [
{...tweet...},
{...tweet...}
],
meta: {
paginate: {
currentPage: 1,
nextPage: 2,
prevPage: null,
totalPages: 11,
totalCount: 51,
perPage: 5
}
}
}
There's a field in meta.paginate
called nextPage
, and this field will either contain the number of the next page of data or be null if there are no more pages to display.
To use that field in our application, we need to add it to be meta
property of collections. To do that, open config/connections.js
and update the parse()
method for collections to look like this:
// config/connections.js
...
parse: function(response) {
this.meta = {
totalCount: response.meta.paginate.totalCount,
perPage: response.meta.paginate.perPage,
nextPage: response.meta.paginate.nextPage
};
return response.data;
}
...
With that change, we'll now be able to discover if there's a next page of data by inspecting tweets.meta.nextPage
.
Next, create the button component by running the following command:
lore generate component LoadMoreButton
Then modify the file to look like this:
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import PayloadStates from '../constants/PayloadStates';
export default createReactClass({
displayName: 'LoadMoreButton',
propTypes: {
lastPage: PropTypes.object.isRequired,
onLoadMore: PropTypes.func.isRequired,
nextPageMetaField: PropTypes.string.isRequired
},
render() {
const {
lastPage,
onLoadMore,
nextPageMetaField
} = this.props;
if(lastPage.state === PayloadStates.FETCHING) {
return (
<div className="footer">
<div className="loader"/>
</div>
);
}
if (!lastPage.meta[nextPageMetaField]) {
return (
<div className="footer"/>
);
}
return (
<div className="footer">
<button className="btn btn-default btn-lg" onClick={onLoadMore}>
Load More
</button>
</div>
);
}
});
import React from 'react';
import PropTypes from 'prop-types';
import PayloadStates from '../constants/PayloadStates';
class LoadMoreButton extends React.Component {
render() {
const {
lastPage,
onLoadMore,
nextPageMetaField
} = this.props;
if(lastPage.state === PayloadStates.FETCHING) {
return (
<div className="footer">
<div className="loader"/>
</div>
);
}
if (!lastPage.meta[nextPageMetaField]) {
return (
<div className="footer"/>
);
}
return (
<div className="footer">
<button className="btn btn-default btn-lg" onClick={onLoadMore}>
Load More
</button>
</div>
);
}
}
LoadMoreButton.propTypes = {
lastPage: PropTypes.object.isRequired,
onLoadMore: PropTypes.func.isRequired,
nextPageMetaField: PropTypes.string.isRequired
};
export default LoadMoreButton;
import React from 'react';
import PropTypes from 'prop-types';
import PayloadStates from '../constants/PayloadStates';
class LoadMoreButton extends React.Component {
static propTypes = {
lastPage: PropTypes.object.isRequired,
onLoadMore: PropTypes.func.isRequired,
nextPageMetaField: PropTypes.string.isRequired
};
render() {
const {
lastPage,
onLoadMore,
nextPageMetaField
} = this.props;
if(lastPage.state === PayloadStates.FETCHING) {
return (
<div className="footer">
<div className="loader"/>
</div>
);
}
if (!lastPage.meta[nextPageMetaField]) {
return (
<div className="footer"/>
);
}
return (
<div className="footer">
<button className="btn btn-default btn-lg" onClick={onLoadMore}>
Load More
</button>
</div>
);
}
}
export default LoadMoreButton;
If everything went well, your application should now look like this. Still exactly the same :)
Below is a list of files modified during this step.
import auth from '../src/utils/auth';
export default {
default: {
apiRoot: 'http://localhost:1337',
headers: function() {
return {
Authorization: `Bearer ${auth.getToken()}`
};
},
collections: {
properties: {
parse: function(response) {
this.meta = {
totalCount: response.meta.paginate.totalCount,
perPage: response.meta.paginate.perPage,
nextPage: response.meta.paginate.nextPage
};
return response.data;
}
}
}
}
};
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import PayloadStates from '../constants/PayloadStates';
export default createReactClass({
displayName: 'LoadMoreButton',
propTypes: {
lastPage: PropTypes.object.isRequired,
onLoadMore: PropTypes.func.isRequired,
nextPageMetaField: PropTypes.string.isRequired
},
render() {
const {
lastPage,
onLoadMore,
nextPageMetaField
} = this.props;
if(lastPage.state === PayloadStates.FETCHING) {
return (
<div className="footer">
<div className="loader" />
</div>
);
}
if (!lastPage.meta[nextPageMetaField]) {
return (
<div className="footer" />
);
}
return (
<div className="footer">
<button className="btn btn-default btn-lg" onClick={onLoadMore}>
Load More
</button>
</div>
);
}
});
import React from 'react';
import PropTypes from 'prop-types';
import PayloadStates from '../constants/PayloadStates';
class LoadMoreButton extends React.Component {
render() {
const {
lastPage,
onLoadMore,
nextPageMetaField
} = this.props;
if(lastPage.state === PayloadStates.FETCHING) {
return (
<div className="footer">
<div className="loader" />
</div>
);
}
if (!lastPage.meta[nextPageMetaField]) {
return (
<div className="footer" />
);
}
return (
<div className="footer">
<button className="btn btn-default btn-lg" onClick={onLoadMore}>
Load More
</button>
</div>
);
}
}
LoadMoreButton.propTypes = {
lastPage: PropTypes.object.isRequired,
onLoadMore: PropTypes.func.isRequired,
nextPageMetaField: PropTypes.string.isRequired
};
export default LoadMoreButton;
import React from 'react';
import PropTypes from 'prop-types';
import PayloadStates from '../constants/PayloadStates';
class LoadMoreButton extends React.Component {
static propTypes = {
lastPage: PropTypes.object.isRequired,
onLoadMore: PropTypes.func.isRequired,
nextPageMetaField: PropTypes.string.isRequired
};
render() {
const {
lastPage,
onLoadMore,
nextPageMetaField
} = this.props;
if(lastPage.state === PayloadStates.FETCHING) {
return (
<div className="footer">
<div className="loader" />
</div>
);
}
if (!lastPage.meta[nextPageMetaField]) {
return (
<div className="footer" />
);
}
return (
<div className="footer">
<button className="btn btn-default btn-lg" onClick={onLoadMore}>
Load More
</button>
</div>
);
}
}
export default LoadMoreButton;
Next we'll create the second component we'll need for Infinite Scrolling.