Skip to main content

[ Part 3 ] First Async call, redux-thunk


Previous Part (adding redux): http://dev.basharallabadi.com/2018/09/part-2-nutracker-reactjs-application.html

By default the store only understands object dispatched actions, i.e. it won't support async calls out of the box neither functions, which conflicts with our need to call an api asynchronously and get the results and returns those results to our reducers to update the state.


Redux Thunk

The simplest approach to achieve what we need is to use something called middleware in redux that can pre process our actions and then proceed to the store when it's done.
Redux thunk is a middleware library that knows how to handle a function received as a dispatched action from a component then based on the result it can dispatch more actions to the store to notify our reducers with the results.
mainly we use it to process async calls and based on the result (success/fail) we ask it to dispatch the proper actions when.

First lets update our foodRepo to actually call an api:
- install corss-fetch npm install --save cross-fetch to use the fetch API and get promises for our async calls.
- renamed the mock method in foodRepo to findFoodMock(), and created new one for the real call which does a fetch call to our api and parse the json body.
- I added this in the package.json: `proxy": "http://localhost:8080` to avoid Cross origin errors so react will proxy requests to this server through the development server.

findFood(name) {
return fetch(`/api/food/search?name=${name}`)
.then(response => response.json());
}

Actions Change

was:

export const SEARCH_FOOD = 'SEARCH_FOOD';
export function searchFood(term) {
 console.log(`in searchFood ${term}`);
 return {
  type: SEARCH_FOOD,
  term
 }
}
Let's change our actions to make an async call, we need two actions  :
- one to declare the call has started (so components can render loading spinner for example)
- another one to handle the result of the call
we already have SEARCH_FOOD action but now, it will now be used to:
- notify the reducers that the call started instead
to send the ajax call we will introduce a new function (fetchFood) that will:
- invoke the ajax call and host the logic to handle the promise result
- dispatch SEARCH_FOOD
the way we will handle the ajax call result is by dispatching a new action with the result as payload:
 RECEIVE_SEARCH_FOOD_RESULTS
after changes:

Reducers

modifed my reducers as well:
- if the action is SEARCH_FOOD it will set a flag that we are fetching data
- if the action is RECEIVE_SEARCH_FOOD_RESULTS, we will handle the results for that term, and update the state with the results array and unset the fetching flag.

what changes on the component side?

Previously in FoodSearch.js we dispatched the searchFood() action creator result (what builds SEARCH_FOOD action payload )
- the dispatch(searchFood(term)) will change now to dispatch(fetchFood(term))
- this new action creator returns a function that takes dispatch as parameter (to use it later on)

but as we said earlier: the store doesn't understand function actions by default and if you run the app now you will get this error message
Error: Actions must be plain objects. Use custom middleware for async actions.
so we will:
- install redux-thunk run npm install --save redux-thunk
- modify our store creation logic:
import thunkMiddleware from 'redux-thunk';
// lines omitted...
const store = createStore(rootReducer, applyMiddleware(thunkMiddleware));
- running the code will show results from server.

Source for day 3: https://github.com/blabadi/react-nutracker/tree/day3/async-api-call
references: https://redux.js.org/advanced/asyncactions

Comments

Popular posts from this blog

Android RecyclerView - Adding Empty View

So RecyclerView was introduced to replace List view and it's optimized to reuse existing views and so it's faster and more efficient as stated in the documentation: https://developer.android.com/training/material/lists-cards.html While using it, I faced the issue of missing a useful functionality that is implemented in ListView. that feature is setting an empty view in case there was no records. In ListView it was as simple as this View emptyView = findViewById(R.id.mylist_empty_view); ListView  myList = .... myList.setEmptyView(emptyView); but this method doesn't exist for recycler view so we need a work around until android team fixes this. and here are the screen shots of both list view and recycler view fix List view : Recycler view : here is how I fixed it: here is the content of empty_view, it can be anything. Enjoy.

[PART 5] NuTracker ReactJS app - Add Login & Profile using Router

In the previous part we finished the dashboard read functionality, now we want to add the skeleton for other pages: - Login   In this page the user will be able to login to their account and the dashboard won't show unless the user is logged in. - Profile In this page the user will be able to update their daily nutrition goals that they can track in the dashboard. to be able to have multiple 'pages' in react and navigate from one to one, we need something that can switch the rendered content based on what we want, we can do that with if statements in the App components and store some location state, but why invent the wheel. React Router every major single page app web framework has the routing concept and functionality to interact with the usual browser urls and switch the content based what user should see. for example on the profile page I want the url path to be /profile, and for login to be /login and so on. in more advanced cases you want the users

Microservices 101, Docker & spring boot sample [Windows 10, home]

This is a very simplistic article :) if you are looking for a deep dive in microservices, see my state-of-the-art microservices full archeticture here: http://dev.basharallabadi.com/2019/03/part-1-spring-state-of-art.html   What are micro services? It's an architectural model for web services that basically requires each service** to be completely independent and loosely coupled from other consumer services, or services that it depends on. and it's not a new idea but it's catching pace in today large scale web applications. ** (by service we mean a component that controls and implements the business logic in a self contained manner, like orders service, products catalog service, accounts management service, all of these have their domain and can be clearly separated)   Why micro services emerged ? 1- Easy to scale services: if you have a single application and all the services share the same code base and war (package) then if you receive high demand on one