Quickstart
A quick dive into getting started with Lore
A quick dive into getting started with Lore
In this step we'll hide tweets that have been deleted.
You can view the finished code for this step by checking out the
optimistic.6
branch of the completed project.
Deleted tweets are still visible in the application, even though they don't exist on the server.
Filter them out of the data displayed in the Feed.
Update the render()
method of the Feed
component to look like this:
// src/components/Feed.js
import PayloadStates from '../constants/PayloadStates';
...
render() {
const { timestamp } = this.state;
return (
<div className="feed">
...
<InfiniteScrollingList
select={(getState) => {
return getState('tweet.find', {
where: {
where: {
createdAt: {
'<=': timestamp
}
}
},
pagination: {
sort: 'createdAt DESC',
page: 1
},
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
});
}}
row={(tweet) => {
return (
<Tweet key={tweet.id || tweet.cid} tweet={tweet} />
);
}}
refresh={(page, getState) => {
return getState('tweet.find', _.defaultsDeep({
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
}, page.query));
}}
selectNextPage={(lastPage, getState) => {
const lastPageNumber = lastPage.query.pagination.page;
return getState('tweet.find', _.defaultsDeep({
pagination: {
page: lastPageNumber + 1
},
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
}, lastPage.query));
}}
selectOther={(getState) => {
return getState('tweet.all', {
where: function(tweet) {
const isOptimistic = !tweet.id;
const isNew = moment(tweet.data.createdAt).diff(timestamp) > 0;
return isOptimistic || isNew;
},
sortBy: function(model) {
return -moment(model.data.createdAt).unix();
},
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
});
}}
/>
</div>
);
}
In the code above, we've added several exclude()
functions to tell getState()
what data we do NOT want included.
If everything went well, your application should now look like this (exactly the same).
Below is a list of files modified during this step.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import _ from 'lodash';
import moment from 'moment';
import PayloadStates from '../constants/PayloadStates';
import InfiniteScrollingList from './InfiniteScrollingList';
import Tweet from './Tweet';
export default createReactClass({
displayName: 'Feed',
getInitialState() {
return {
timestamp: new Date().toISOString()
};
},
render() {
const { timestamp } = this.state;
return (
<div className="feed">
<h2 className="title">
Feed
</h2>
<InfiniteScrollingList
select={(getState) => {
return getState('tweet.find', {
where: {
where: {
createdAt: {
'<=': timestamp
}
}
},
pagination: {
sort: 'createdAt DESC',
page: 1
},
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
});
}}
row={(tweet) => {
return (
<Tweet key={tweet.id || tweet.cid} tweet={tweet} />
);
}}
refresh={(page, getState) => {
return getState('tweet.find', _.defaultsDeep({
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
}, page.query));
}}
selectNextPage={(lastPage, getState) => {
const lastPageNumber = lastPage.query.pagination.page;
return getState('tweet.find', _.defaultsDeep({
pagination: {
page: lastPageNumber + 1
},
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
}, lastPage.query));
}}
selectOther={(getState) => {
return getState('tweet.all', {
where: function(tweet) {
const isOptimistic = !tweet.id;
const isNew = moment(tweet.data.createdAt).diff(timestamp) > 0;
return isOptimistic || isNew;
},
sortBy: function(model) {
return -moment(model.data.createdAt).unix();
},
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
});
}}
/>
</div>
);
}
});
import React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import moment from 'moment';
import PayloadStates from '../constants/PayloadStates';
import InfiniteScrollingList from './InfiniteScrollingList';
import Tweet from './Tweet';
class Feed extends React.Component {
constructor(props) {
super(props);
this.state = {
timestamp: new Date().toISOString()
};
}
render() {
const { timestamp } = this.state;
return (
<div className="feed">
<h2 className="title">
Feed
</h2>
<InfiniteScrollingList
select={(getState) => {
return getState('tweet.find', {
where: {
where: {
createdAt: {
'<=': timestamp
}
}
},
pagination: {
sort: 'createdAt DESC',
page: 1
},
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
});
}}
row={(tweet) => {
return (
<Tweet key={tweet.id || tweet.cid} tweet={tweet} />
);
}}
refresh={(page, getState) => {
return getState('tweet.find', _.defaultsDeep({
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
}, page.query));
}}
selectNextPage={(lastPage, getState) => {
const lastPageNumber = lastPage.query.pagination.page;
return getState('tweet.find', _.defaultsDeep({
pagination: {
page: lastPageNumber + 1
},
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
}, lastPage.query));
}}
selectOther={(getState) => {
return getState('tweet.all', {
where: function(tweet) {
const isOptimistic = !tweet.id;
const isNew = moment(tweet.data.createdAt).diff(timestamp) > 0;
return isOptimistic || isNew;
},
sortBy: function(model) {
return -moment(model.data.createdAt).unix();
},
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
});
}}
/>
</div>
);
}
}
export default Feed;
import React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import moment from 'moment';
import PayloadStates from '../constants/PayloadStates';
import InfiniteScrollingList from './InfiniteScrollingList';
import Tweet from './Tweet';
class Feed extends React.Component {
constructor(props) {
super(props);
this.state = {
timestamp: new Date().toISOString()
};
}
render() {
const { timestamp } = this.state;
return (
<div className="feed">
<h2 className="title">
Feed
</h2>
<InfiniteScrollingList
select={(getState) => {
return getState('tweet.find', {
where: {
where: {
createdAt: {
'<=': timestamp
}
}
},
pagination: {
sort: 'createdAt DESC',
page: 1
},
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
});
}}
row={(tweet) => {
return (
<Tweet key={tweet.id || tweet.cid} tweet={tweet} />
);
}}
refresh={(page, getState) => {
return getState('tweet.find', _.defaultsDeep({
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
}, page.query));
}}
selectNextPage={(lastPage, getState) => {
const lastPageNumber = lastPage.query.pagination.page;
return getState('tweet.find', _.defaultsDeep({
pagination: {
page: lastPageNumber + 1
},
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
}, lastPage.query));
}}
selectOther={(getState) => {
return getState('tweet.all', {
where: function(tweet) {
const isOptimistic = !tweet.id;
const isNew = moment(tweet.data.createdAt).diff(timestamp) > 0;
return isOptimistic || isNew;
},
sortBy: function(model) {
return -moment(model.data.createdAt).unix();
},
exclude: function(tweet) {
return tweet.state === PayloadStates.DELETED;
}
});
}}
/>
</div>
);
}
}
export default Feed;
In the next section we'll learn how to normalize an API response to reduce the number of network requests.