It’s the last part of series about creating react redux app. In previous two parts I described how to create classic react redux app, then I made full test coverage of app post module and replaced all redux stuff (action types, action creators, reducer and container) by 7 lines of — a library created to make redux development more declarative. Redux Lazy In this article I’ll show how to add logic in react redux app using , and . redux-observable recompose reselect Links to previous parts: _Each time working with redux in react app we spend a lot of time to make action types, action creators, reducers… Most…_hackernoon.com React — redux for lazy developers and _In this article I’m continue to discuss creating react redux app using redux-lazy._medium.com React — redux for lazy developers. Part 2 I’ll use code from the second part. You can find it on . github I updated , new … redux-lazy : options docs tests After small refactoring you can get 100% the same results like using redux stuff (even better — see form ): onSubmit rl.js (src/modules/post/rl/index.js) Before: RL 'redux-lazy'; import from rl = RL('post');rl.addAction('title', { title: '' });rl.addAction('body', { body: '' });rl.addAction('submit'); const new result = rl.flush(); const result; export default And now: RL 'redux-lazy'; import from rl = RL('post');rl.addAction('title',{ title: '' }, );rl.addAction('body',{ body: '' }, );rl.addAction('submit',{}, ); const new { isFormElement: true, asParams: 'title' }, { isFormElement: true, asParams: 'body' }, { isForm: true }, result = rl.flush(); const result; export default Component (src/modules/post/components/index.jsx) Before: React 'react'; PropTypes 'prop-types'; import from import from PostComponent = props => (<form const onSubmit={(event) => {event.preventDefault();props.submitAction();}} <h1>Our form example</h1> <div> <input type="text" **onChange={event => props.titleAction({ title: event.target.value })}** value={props.title} /> </div> <div> <textarea **onChange={event => props.bodyAction({ body: event.target.value })}** value={props.body} /> </div> <div> <input type="submit" value="Submit" /> </div> </form>); PostComponent.propTypes = {title: PropTypes.string.isRequired,body: PropTypes.string.isRequired,titleAction: PropTypes.func.isRequired,bodyAction: PropTypes.func.isRequired,submitAction: PropTypes.func.isRequired,}; PostComponent; export default And now: React 'react'; PropTypes 'prop-types'; import from import from PostComponent = props => ( <h1>Our form example</h1><div><inputtype="text" value={props.title}/></div><div><textarea value={props.body}/></div><div><input type="submit" value="Submit" /></div></form>); const <form onSubmit={props.submitAction}> onChange={props.titleAction} onChange={props.bodyAction} PostComponent.propTypes = {title: PropTypes.string.isRequired,body: PropTypes.string.isRequired,titleAction: PropTypes.func.isRequired,bodyAction: PropTypes.func.isRequired,submitAction: PropTypes.func.isRequired,}; PostComponent; export default And no in action: payload And again... Store is a . Setters are and , getters are for . All logic should be in other place. It could be like stored procedures — a lot of logic and no way for good testing. database action creators reducers selectors connect mapStateToProps No logic inside reducers or actions. As I said before I like to work with React in a functional way. I use components like a pure functions. It’s easy to describe as a JS arrow function: . props => JSX When you need to add local state or react component lifecycle you can use — a react utility belt for function components and higher-order components. recompose I created another article with some examples: _As you may know working with react you can use functions or classes — work with stateless and stateful components. In…_blog.cloudboost.io React: functional way We will use recompose to get data about post when component was rendered. lifecycle First, we need to install it: yarn add recompose Then we should create wrapper for our component — high order component (HOC). Let’s create : src/modules/post/containers/lifecycle.js { lifecycle } 'recompose'; import from lifecycle({componentDidMount() { .props.loadAction();},}); export default this And update our Redux Lazy model ( ): src/modules/post/rl/index.js RL 'redux-lazy'; import from rl = RL('post'); const new rl.addAction('title', { title: '' }, { isFormElement: , asParams: 'title' });rl.addAction('body', { body: '' }, { isFormElement: , asParams: 'body' });rl.addAction('submit', {}, { isForm: });rl.addAction('load');rl.addAction('loaded', { title: '', body: '' }, { asParams: ['title', 'body'] });rl.addAction('error', { error: }, { asParams: 'error' }); true true true null result = rl.flush(); const {nameSpace,actions: {bodyAction,errorAction,loadAction,loadedAction,submitAction,titleAction,},types: {POST_BODY,POST_ERROR,POST_LOAD,POST_LOADED,POST_SUBMIT,POST_TITLE,},} = result; const result; export default {nameSpace,bodyAction,errorAction,loadAction,loadedAction,submitAction,titleAction,POST_BODY,POST_ERROR,POST_LOAD,POST_LOADED,POST_SUBMIT,POST_TITLE,}; export I added to start loading post data, — show that we don’t have errors and — save error in store if we have a problems, then we can show it on the page. load action loaded action error action I export , and to avoid magic each time when I need to import it in other place like epics or tests. nameSpace types actions And we need to wrap our Post component in module entry point ( ): src/modules/post/index.js PostComponent './components'; rl './rl'; lifecycleContainer './containers/lifecycle'; import from import from import from { Container: PostContainer } = rl; const PostContainer( (PostComponent)); export default lifecycleContainer Check it: We can see our loadAction on starting. Our next step is making ajax request and manage side effects. There are a lot of tools to work with async action using redux. As redux is totally function it doesn’t have a side effects. And you should manage it using other tools like , , or . redux-thunk redux-promise redux-saga redux-observable About redux-thunk and redux-promise you can read in article: _Thunks, sagas, effects and loops. My brief opinion on some of the Redux side effect middlewares._medium.com Redux side effects and me I don’t use those tools because it’s created for making small actions. For example, make one ajax request for app... But if you are making a great app, you need to manage a lot of stuff like ajax request, making many actions at the same time… So I see only two ways: redux-saga and redux-observable. I choose redux observable because it’s implementation of FRP — functional reactive programming using . It’s more declarative — less code, more sense. Rx.js You can read more about redux-observable: _Edit description_redux-observable.js.org Introduction · redux-observable And see a great video presentation: And if you want to read some articles to compare both tools: _Redux-Saga V.S. Redux-Observable === ### Redux-Saga V.S. Redux-Observable 1. Metal Model 2. Side_hackmd.io Redux-Saga V.S. Redux-Observable - HackMD and _And Why Do I Care?_shift.infinite.red Redux-Observable Epics vs Redux-Sagas I totally recommend to read first link. The main pattern of redux-observable is epics. Each time when you dispatch action, redux uses reducers, middlewares and subscribed tools. Each time when you dispatch action, redux-observable runs epics created as a handlers for the action type. Before we start to create our first epic we need to install it: yarn add redux-observable@0.19.0 While we rare waiting for redux-observable release we should use Rx.js version 5. To use redux-observable ( ) we need to create root epic where we can import epics from our modules and add it as middleware to our store. see docs src/epics.js { combineEpics } 'redux-observable'; import from postEpics './modules/post/epics'; import from rootEpic = combineEpics(postEpics); const rootEpic; export default src/store.js { createStore, applyMiddleware } 'redux'; logger 'redux-logger'; import from import { createEpicMiddleware } from 'redux-observable'; import from reducers './reducers';**import rootEpic from './epics';** import from const epicMiddleware = createEpicMiddleware(rootEpic); store = createStore(reducers,applyMiddleware(logger, ),); const epicMiddleware store; export default How to use code splitting and dynamic import of reducers and epics I’ll show in next articles thanks to my new library — . wpb Just to remember, we are using service to get post data. It’s just an example. https://jsonplaceholder.typicode.com/ And our post module epic: src/modules/post/epics/index.js { combineEpics } 'redux-observable'; import from loadEpic './load'; import from combineEpics(loadEpic); export default If we have more than one epic we need to combine it. For this example I’ll show only load epic, but you can add submit epic to update story on the server. src/modules/post/epics/load.js 'rxjs'; { Observable } 'rxjs/Observable'; import import from axios 'axios'; import from {POST_LOAD,loadedAction,titleAction,bodyAction,errorAction,} '../rl'; import from loadEpic = action$ => action$.ofType(POST_LOAD).switchMap(() => { request = axios.get('https://jsonplaceholder.typicode.com/posts/1').then(({ data }) => data); const const **return** Observable .fromPromise(request) .switchMap(({ title, body }) => Observable .of(loadedAction()) .concat(Observable.of(titleAction(title))) .concat(Observable.of(bodyAction(body)))); }).catch(error => Observable.of(errorAction(error))); loadEpic; export default It can be complicated at the first time. Here I import action type to run epic (we have event with this action from recompose ) and actions: — to show that we have a good response or — if we have a problems. and actions we use to set data to our store. POST_LOAD lifecycleContainer loaded error Title body Using we can create stream from promise created by axios. Observable.fromPromise() Then we can create a new stream — . Observable.of(loadedAction()) And concat streams for setting title and body from response. If we have an error we need to catch it and return a new stream with error data (each time we need to return stream). We can check results: Now small update of our component: React 'react'; PropTypes 'prop-types'; import from import from PostComponent = props => (<form onSubmit={props.submitAction}><h1>Our form example</h1><div><inputtype="text"onChange={props.titleAction}value={props.title}/></div><div><textareaonChange={props.bodyAction}value={props.body}/></div><div><input type="submit" value="Submit" /></div> </form>); const {props.error && (<div>{props.error.message}</div>)} PostComponent.propTypes = {title: PropTypes.string.isRequired,body: PropTypes.string.isRequired, titleAction: PropTypes.func.isRequired,bodyAction: PropTypes.func.isRequired,submitAction: PropTypes.func.isRequired,}; error: PropTypes.objectOf(PropTypes.any), PostComponent.defaultProps = {error: null,}; PostComponent; export default I added error message to the form. To emulate error I’ll change url to and check result: https://jsonplaceholder.typicode.com/posts/test Now we can show error on page to see that we have 404 Page Not Found error for wrong url. And testing: nock 'nock'; { expect } 'chai'; { ActionsObservable } 'redux-observable'; import from import from import from {loadAction,loadedAction,titleAction,bodyAction,POST_ERROR,} '../../../../src/modules/post/rl'; import from epics '../../../../src/modules/post/epics'; import from describe('Testing post module loadEpic', () => {it('should test loadEpic without error', (done) => { title = 'title'; body = 'body'; const const nock('https://jsonplaceholder.typicode.com') .get('/posts/1') .reply(200, { title, body }); **const** action$ = ActionsObservable._of_(loadAction()); **const** expectedOutputActions = \[ loadedAction(), titleAction(title), bodyAction(body), \]; epics(action$) .toArray() .subscribe((actualOutputActions) => { expect(actualOutputActions).to.be.eql(expectedOutputActions); done(); }); }); it('should test loadEpic with error', (done) => { message = 'Request failed with status code 404'; const nock('https://jsonplaceholder.typicode.com') .get('/posts/1') .reply(404); **const** action$ = ActionsObservable._of_(loadAction()); epics(action$) .toArray() .subscribe((actualOutputActions) => { expect(actualOutputActions).to.have.length(1); expect(actualOutputActions\[0\].type).to.be.equal(POST\_ERROR); expect(actualOutputActions\[0\].error.message).to.be.equal(message); done(); }); });}); I use to mock HTTP requests. nock To test epic you just need to create a stream using ActionsObservable. Then put it to epic as the first parameter (the second is a store) and subscribe to output. You can use epics not only for ajax requests. You can switch a new action: action$ => actions$.ofType(REQUEST1).mapTo(request2Action) With store: (action$, store) => actions$.ofType(REQUEST1).switchMap((action) => {const state = store.getState(); console.log(action, state); return Observable.of(newAction()); }); I can stop on this. But I want to say a couple of words about performance. My last updates ( and options) help me to use Redux Lazy actions as links in react components. It’s a good stuff to avoid useless rendering. isForm isFormElement But we should not forget about react-redux connect HOC. To get data from store we need to use selectors. As we use Redux Lazy Container we should not think about this because it’s to simple and it uses object links to store data: { connect } 'react-redux'; post, { nameSpace } '../rl'; import from import from mapStateToProps = state => state[nameSpace]; mapDispatchToProps = { ...post.actions }; const const connect(mapStateToProps, mapDispatchToProps); export default But If I need to change data before put it to component or get data from other module, each time I’ll get a new object and React will re-render it again and again even if data all time is the same. — selector library for Redux, helps us with this problem. Reselect Let’s install it and I’ll show how to use. yarn add reselect And our complicated container: { connect } 'react-redux'; { createSelector } 'reselect'; import from import from post, { nameSpace } '../rl'; import from postSelector = state => ({title: state[nameSpace].title,body: state[nameSpace].body,titleLength: state[nameSpace].title.length,bodyLength: state[nameSpace].body.length,}); const mapStateToProps = createSelector(postSelector,newPost => newPost,); mapDispatchToProps = { ...post.actions }; const const connect(mapStateToProps, mapDispatchToProps); export default I added and as a properties just for example. In real app you can get part from store or some parts and merge it. In any way without reselect you will create a new object each time and react will re-render components even if data is the same. titleLength bodyLength Reselect checks data inside of a new object and return each time link to the same object from memory. React will see the same link and won’t re-render component. This is the last part of series about Redux Lazy. Please ask your questions in comments and don’t forget to star it on . github