Skip to content

Instantly share code, notes, and snippets.

@eddiecooro
Last active June 9, 2019 14:05
Show Gist options
  • Save eddiecooro/50c44ec633e6f1a2af1b86767d3ba138 to your computer and use it in GitHub Desktop.
Save eddiecooro/50c44ec633e6f1a2af1b86767d3ba138 to your computer and use it in GitHub Desktop.
render() {
return withPagination('users', 'followers', 'https://.../users')(UsersView)
}
const UsersView = ({ isLoading, isLoadingMore, hasNext, reload, loadMore, data }) => {
...
}
export default withPagination('users', 'followers', 'https://.../users')(UsersView)
const reload = (firstPage, sliceName, paginationName) => dispatch => {
Axios.get(firstPage).then(res => {
dispatch({
type: paginationActionTypes.PAGINATE_RELOAD,
sliceName: sliceName,
paginationName,
payload: {
first: firstPage,
next: res.data.next,
data: res.data.items,
},
});
});
};
const loadMore = (sliceName, paginationName) => (dispatch, getState) => {
Axios.get(getState()[sliceName].paginations[paginationName].next).then(res => {
dispatch({
type: paginationActionTypes.PAGINATE_LOAD_MORE,
sliceName,
paginationName,
payload: {
next: res.data.next,
previous: res.data.previous,
data: res.data.items,
},
});
});
};
paginations: {
main_page: {
datas: [22],
first: '...',
previous: null,
next: '...'
},
followers: {
datas: [22],
first: '...',
previous: null,
next: '...',
},
followings: {
datas: [22, 24],
first: '...',
previous: '...',
next: null,
}
}
const emptyArray = [];
const createSelectorsFor = sliceName => {
const selectors = {
getPagination: (state, paginationName) => state[sliceName].paginations[paginationName],
exists: (state, paginationName) => !!getPagination(state, paginationName),
hasNext: (state, paginationName) => selectors.exists(state, paginationName) && !!selectors.getPagination(state, paginationName).next,
getData: (state, paginationName) => selectors.exists(state, paginationName) ? selectors.getPagination(state, paginationName).data.map(d => state[sliceName].data[d]) : emptyArray,
};
return selectors;
}
{
paginations: {...},
data: {
22: {
id: 22,
name: 'Eddie',
},
24: {
id: 24,
name: 'S_eft',
}
}
}
const rootReducer = combineReducers({
users: withPagination(usersReducer, 'users');
})
export default (state = [], action) => {
switch(action.type) {
case paginateActionTypes.LOAD_DATA:
return state.concat(action.payload.data);
default return state
}
}
const withPagination = (sliceName, paginationName, firstPage) => WrappedComponent => {
class InnerClass extends Component {
state = {
isLoading: false,
isLoadingMore: false,
};
static emptyArray = [];
componentDidMount() {
this.reload();
}
reload() {
if (this.state.isLoading) return;
this.setState({ isLoading: true });
this.props.reload(firstPage, sliceName, paginationName).finally(() => {
this.setState({ isLoading: false });
});
}
loadMore() {
if (this.state.isLoadingMore || !this.props.pagination.next) return;
this.setState({ isLoadingMore: true });
this.props.loadMore(sliceName, paginationName).finally(() => {
this.setState({ isLoadingMore: false });
});
}
render() {
const { pagination } = this.props;
return (
<WrappedComponent
isLoading={this.state.isLoading}
isLoadingMore={this.state.isLoadingMore}
hasNext={!!this.props.pagination.next}
reload={this.reload}
loadMore={this.loadMore}
data={pagination ? pagination.data : InnerClass.emptyArray}
/>
);
}
}
return connect(
state => ({
pagination: state[sliceName].paginations[paginationName],
}),
{
loadMore: paginateActionCreators.loadMore,
reload: paginateActionCreators.reload,
},
)(InnerClass);
};
const withPagination = (reducer, sliceName) => (state = { paginations: {} }, action) => {
if (action.sliceName === sliceName && action.paginationName) {
switch (action.type) {
case paginateActionTypes.PAGINATE_RELOAD:
return {
paginations: {
...state.paginations,
[action.paginationName]: {
first: action.payload.first || state.paginations[paginationName].first,
next: action.payload.next || state.paginations[paginationName].next,
previous: null,
datas: action.payload.data.map(d => d.id),
},
},
data: reducer(state, { type: paginateActionTypes.LOAD_DATA, payload: { data: action.payload.data } }),
};
case paginateActionTypes.PAGINATE_LOAD_NEXT:
return {
paginations: {
...state.paginations,
[action.paginationName]: {
first: state.paginations[paginationName].first,
next: action.payload.next,
previous: action.payload.previous,
datas: state.paginations[paginationName].concat(action.payload.data.map(d => d.id)),
},
},
data: reducer(state, { type: paginateActionTypes.LOAD_DATA, payload: { data: action.payload.data } }),
};
}
}
return { ...state, data: reducer(state.data, action) };
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment