Reading and Writing data with ReactJS + Redux

When it comes to learning ReactJS with Redux, there are numerous really helpful documents and tutorials online, including 'Redux Usage with React'

However, when closing the gap between the online examples and production code, a gaping hole emerges: "How do you get data in and out of your React + Redux app?".

Whether you are building a React native app or using React for the web you reach a point where you need to read data that represents the current state, and then save changes to that data.

I found the documentation at this point a little fuzzy, with reference being made to 'side-effects'.  Now, I personally see the loading and saving of data in an application as more than a side effect.  But I kept on coming back to diagrams like this:
Apologies, but I can't recall the original source for this.  If it is you, please do get in touch and I will give you the credit


And this:



But what I really needed was a diagram like this:



Now the 'side-effect' nature of this data access becomes clear.

If you are on this same journey of discovery, hopefully you will find the steps below helpful.
The examples are for React on the web, but the principle is the same for React native.

(Apologies to JavaScript purists, but these examples are in TypeScript)

1. Use redux-thunk when you configure the store.
export default function configureStore(): Redux.Store {
    return createStore(
        rootReducer,
        applyMiddleware(
            ReduxThunk // lets us dispatch functions for calls to web server
        )
    );
}
2. Use superagent (or similar) in an API class to make the http call.
export default class xxxApi {
    public constructor(private baseUrl: string) {}

    public getAbc(): Promise {
        return new Promise((resolve: any, reject: any): any => {
            let request = Superagent.get(this.baseUrl + '/abc').send({…});
            request.set({ … });
            request.end((error: any, response: any) => {…});
        });
    }
}
3. Create an Action Creator which handles the response of the API function.
export function receiveAbc(json: any): IAction {
 
    return {
        type: xxxTypes.LOAD_ABC,
        payload: json,      
    };
}
3b. Possibly including a reducer to update the store.
export default function AbcReducer(state:AbcState, action: IAction): any {
    switch (action.type) {
        case xxxypes.LOAD_ABC: {
            // immutable state change
        }
    }
}
4. Create an ActionCreator which calls the API function.
export function fetchAbc(): any {
    // thunk middleware passes dispatch, state & container in
    return function(dispatchEvent: Function, getState: Function, container: dependencyContainer): any {
        let state: IStoreState = getState(); // in actions you can read from the store if you need to
        let api: new XxxAPI(state.config.baseUrl);
        api.getAbc()
            .then((json: any) => {
                // process result here
            });
    };
}
5. Wire up the action in the Container Component.
const mapDispatchToProps = (dispatchEvent: any): xxxProps => {
    return {
        ...
        goGetAbc: () => {
            dispatchEvent(xxxActions.fetchAbc());
        }
    };
};
6. When the response for the call returns, dispatch another event to update the store.
export function fetchAbc(): any {  
    return function(dispatchEvent: Function, getState: Function): any {
        let state: IStoreState = getState();
        let api: new XxxAPI(state.config.baseUrl);
        api.getAbc()
            .then((json: any) => {
                // process data
                dispatchEvent(receiveAbc(json));
                // removing loading indicator (or similar)
                dispatchEvent(updateUiLoadingStatus());
            });
    };
}



Comments