Data loader for react & redux

Why to use it?

Easy to use

You have to add your initial configurations and then you just ask what you need from the data store.

Efficiency & Consistency

This library fetch and stores your data on reducers normalized, keeping your data updated & consistent, avoiding duplicate entities.

Customization

You can always add custom logic on reducers or on saga middleware.

Show me the difference

Thunk

From 121lines to ~> 9lines

Installation

If you use redux-saga


                        npm i --save redux-relax-saga    
                    

If you use redux-thunk


                        npm i --save redux-relax-thunk
                    

Setting up


                        import { createStore } from 'redux';
                        import DevTools from '../containers/DevTools';
                        import rootReducer from '../reducers';
                        import ReduxRelaxEnchancer from 'redux-relax-thunk';

                        const configs = {
                          dev: true,
                          apiEndpoint: 'https://api.github.com/',//required
                          getHeaders: (state) => ({ }),
                          reducers: {
                            paginate: {
                              totalPageCountField: 'pages', //required
                              totalCountField: 'totalCount', //required
                              currentPageField: undefined //optional
                            },
                          },
                          entities: [
                            {
                              uniqueIdAttribute: 'login', // The field that is used as unique id - Required
                              name: 'users', // Name of the entities field in state- Required
                              itemsField: 'items', // the field on response payload that includes our data
                              singleApiUrl: login => `users/${login.toString()}` // The route to base endpoint to fetch a single entity - Required,
                              apiUrl: login => `repos/${login}/stargazers`, // The route to base endpoint to fetch multiple entities - Required,
                              paginationKey: 'login',
                            }, {
                              uniqueIdAttribute: 'fullName',
                              name: 'repos',
                              itemsField: 'items',
                              singleApiUrl: fullName => `repos/${fullName}`,
                              apiUrl: login => `users/${login}/starred`,
                              paginationKey: 'fullName',
                            },
                          ]
                        }


                        const store = createStore(
                          rootReducer,
                          {},
                          ReduxRelaxEnchancer(configs, [DevTools.instrument()]),
                        );

                        export default store

                    

How to use it?


                    @multiple('repos',  (state, ownProps) => {
                      const { login } = state.router.params; //The pagination key to get all repos for user with username = {login}
                      return { search: login};
                    })
                    @single('users', (state, ownProps) => {
                      const { login } = state.router.params; //The entities key to get user with id = {login}
                      return login;
                    })
                    class UserPage extends Component {

                        componentWillReceiveProps(nextProps) {
                            if (this.props.login !== nextProps.login) {
                              this.props.loadUser(nextProps.login) //You also have loadUser as prop since you asked for @single - users
                              this.props.loadRepos(nextProps.login) //You also have loadRepos as prop since you asked for @multiple - repos
                            }
                        }

                        handleLoadMoreClick() {
                            this.props.loadMoreRepos(this.props.login) // You also have loadMoreRepos as prop since you asked for multiple - repos
                        }
                        
                        render() {
                            ...
                        }
                    };

                    function mapStateToProps(state) {
                      const { login } = state.router.params
                      const {
                        entities: { users, repos }
                      } = state

                      return {
                        login,
                        user: users[login]
                      }
                    }

                    export default connect(mapStateToProps, {
                    })(UserPage)
                    
                

Or without decorators...


                    class UserPage extends Component {
                        componentWillReceiveProps(nextProps) {
                            if (this.props.login !== nextProps.login) {
                                this.props.loadUser(nextProps.login) // You also have loadUser as prop since you asked for single - users
                                this.props.loadRepos(nextProps.login) // You also have loadRepos as prop since you asked for multiple - repos
                            }
                        }

                        handleLoadMoreClick() {
                            this.props.loadMoreRepos(this.props.login) // You also have loadMoreRepos as prop since you asked for multiple - repos
                        }

                        render() {
                            ...
                        }
                    };

                    UserPage = multiple('repos', (state, ownProps) => {
                      const { login } = state.router.params; //The pagination key to get all repos for user with username = {login}
                      return { search: login };
                    })(UserPage);

                    UserPage = single('users', (state, ownProps) => {
                      const { login } = state.router.params; //The entities key to get user with id = {login}
                      return login;
                    })(UserPage)

                    function mapStateToProps(state) {
                      const { login } = state.router.params
                      const {
                        entities: { users, repos }
                      } = state

                      return {
                        login,
                        user: users[login]
                      }
                    }

                    export default connect(mapStateToProps, {
                    })(UserPage)