Saturday, September 15, 2018

[ 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

Thursday, September 13, 2018

[ Part 2 ] Nutracker, ReactJS application - Adding Redux

In the first part we covered how to create components and
how to interact with a mock api to get data for our application.

all of that can be enough to build a react app but it won't scale well
for the following reasons:
1- state will be all over the place  in different container components which means we have to add more layers of components to share common parts of states.
2- the propagation of events can be hard to deal with when the components tree gets deeper and other components (siblings and their children) will probably need to be notified of state changes.


Redux data flow

so there is a library called redux, and redux-react.

this library in simple terms facilitates dispatching application wide events to specific handlers (reducers) that modify the state based on the actions they receive, it then store the whole state after those handlers change it and pass the new state to react framework to rerender our components.
In short: it's an event publish/subscriber tailored to manage a state object.

it worth mentioning that redux itself can be used to manage any state, not only react (state is just a JS object at the end of the day) but redux-react adds helper functions and saves you from writing some boilerplate code that we will see soon.

Part 2 code 

https://github.com/blabadi/react-nutracker/tree/01f265a10363a73f359e45db917306be0e1d6efc



Directories added (to organize but not needed):
- actions
- reducers
Renamed:
components => presentational (not related nor needed to redux)

To think the redux way, we have to look at what our component raise for events
currently we have searchBox on term change, this can be translated to a redux 'action' called SEARCH_FOOD.
Actions have to be objects (by default) and to distinguish each action, we give it a type property which is unique string across the app, they also hold any other properties as needed.
So we want our searchBox to send (dispatch in redux terms) a SEARCH_FOOD action to trigger a call to the mock api and fetch foods that match the user query.

Note that our presentation component (SearchBox) won't change in anyway because it was designed not to need so (see part 1 for details).
 Only our container components will change 
from:
 - managing state locally 
 - being responsible to fetch the data by calling the external api (handle events)
to: 
dispatch actions and receive new state

for the first action it will look like this:

the action is just an object, the function that creates that object is called an action creator.
in our case, it takes term as an argument and returns a simple object .
the SearchBox dispatches that action by using the method: dispatch passed to it from redux store
A lot has changed in this component it no longer has any of the react related code, and the reason is:
that it is now created for us by redux using the connect() helper method from redux-react library.
 
The moment you start using redux our container components become unnecessary to be created manually (repetitive boilerplate code) as they will just have one variant in the code , which is to tell redux what to dispatch on each event (mapDispatchToProps), and how to read the state and pass it to child presentation components (mapStateToProps).

without using the connect utility method we will need something like this

class FoodSearchBox extends Component {
  onTermChange = (term) => {
    store.dispatch(searchFood(term))
  }
  render = () => {
     return <SearchBox  ...
            onTermChange = {this.onTermChange}
            results={toResults(store.getState().searchFoodResults)} />

  }
}

The next question if you look at the code above is where did state.searchFoodResults was created ?
the answer is: in the reducer.

A Reducer is a function that receives (state & action) and returns a new state calculated from the action.

for our case here this is our reducer:



it took the state and if the action is SEARCH_FOOD we filled the state with the mock data.
and returned the new state.

few notes:
- Reducers has to be pure functions (no api calls, no database calls nothing that is not a pure js objects manipulation), in this example I did call foodRepo in the reducer but that's just because it's mock data call, not actual network call, but we will change this next part.
- combineReducers is a method from redux that you pass it all the reducers you have and it will build the state tree out of these. (it's good practice to split reducers based on parts of the state each handles, and not have one gigantic function). if we say want to store user information in the state, we would do so by having a reducer like this :
const user = (state = {}, action) => { ... }
and our state will look like this:

  user: {}, 
  searchFoodResults: [] 
}
and so on, Redux will use the keys (in combineReducers) to build the state and it will also pass that part of the state to that reducer to let it focus on that part of the state so our user reducer will only get a reference to: state.user and not a reference to the whole state tree.

So by now our app hasn't changed functionality wise, but internally it changed a lot, and this is a needed foundation to scale it for a bigger state and more interactions across components.

In the next part I'll explain how we can get rid of the mock data and do an actual async ajax call to an api that will return foods and what will need to change to handle the asynchronous  call.

for more details:
https://redux.js.org/basics/

Saturday, September 8, 2018

[ Part 1] Nutracker, ReactJS application - Creation & first component


Part 1: from scratch

Read the introduction

in this part I'll be explaining the first commit, source code for that can be found here:
https://github.com/blabadi/react-nutracker/tree/f3b998b6e4ba9d2cdeed15ce637066fac0647c1f

Creating the project:

run this command (this is using nodeJS binary) :
npx create-react-app react-nutracker

this will initialize the directories and we are ready to start adding our code.
this is a command line tool created by react team to make initializing as easy as possible because it can be overwhelming for people to configure everything, let's focus on react for now and not the details that can be done later.
see: https://github.com/facebook/create-react-app

you can also start the application and it will work:
npm start

Install bootstrap

npm install --save bootstrap

import bootstrap in the index.js file.
import 'bootstrap/dist/css/bootstrap.min.css';

The First NUtracker Component: Search box




1-  I added the following directories:  components, containers, repos, model


2- in component/search the initial version of SearchBox component:

and used here in Dashboard Component:


Observations:

  • The dashboard component stores the results in the state
  • It passes to the searchBox what to do when the user enters a new search term (onTermChange callback)
  • It also passes the results of the search for the search box to render AFTER fetching the results from the food repo (mock for a call to food REST api). the reason to have this kind of design is to keep search box a dumb component that can be reused again without it being aware of how to get the results. it's only a presentation component (i.e. it just renders html and notifies its container of any user events it receives)
  • The dashboard is a container component, which means it manages one or many presentation components and provide them with the props they need to function either from server or whatever, and it also manages what to do when an event is raised by the child components, in this example it calls foodRepo to get foods based on what the user has input in the box.
  • Note that when we get the results from food repo we store them in the state in a key value generic properties, to allow the search box to render the results without knowing what kind of results it is, it could be foods, articles, cats, whatever.
  • Also the key is needed by react when you render a list of anything or you will get an error, a property called key is needed in the html elements for react to work.
  • foodRepo and model is something I preferred to do, but you can organize the way you want.
result after part 1:



Part two: Adding Redux. : http://dev.basharallabadi.com/2018/09/part-2-nutracker-reactjs-application.html

[ Intro ] Nutracker, ReactJS application Step By Step









I worked before on learning angular 2+, and made a sample functioning app that tracks calories &  macros, called it NUtracker.


For live running version (angular) : here. (buggy as it's just prototype, after registration set your profile goals first otherwise it will look broken).


Main functionalities:

- search for foods from a db
- add new food to the db
- add them as daily entries
- calculate the total daily intake of calories, carbs, fats & protein with respect to the daily goals
- users can set the goals in their profile screen.
- login/registration screen.
- move back and to see other days entries.
- edit/remove entries

Why?

in this series of blogs I'll try to replicate this angular project in react, for two reasons:
1- get a sense of both framework and compare them to each other apple to apple.
2- apply what I learn about react & it's eco-system in a project and solve the problems I face.

The main goal of this blogs series is

To document how an app starts and evolves overtime and how to handle real case needs step by step*

* by step-by-step i don't mean line by line of code, but rather steps in the project and adding functionalities, so each part I'll be talking about a commit or two that aimed to fulfill a need or implement a specific functionality while trying to be focused on new things and not repeating, so you will need to figure out some details. I won't suggest following my exact example but rather build your own app wit this as an example of how and what to expect.

Learn React

I mainly learned react (serious learning) from this book: Full Stack React
the good thing about books is that you get a good foundation and intuition of  how things work and why in more details than other sources, However, you can learn reactJS basics anywhere in 1 hour or so which can be enough to follow this series.

Prerequisites:

- you know html , css, javascript ES6+, bootstrap
- you know what npm is and what package.json and got NodeJS installed.
- you know what reactJS is as framework and the basic concepts (state, props, reactivity, render( ), JSX, components) but didn't necessarily worked with react in a project.

Repository

https://github.com/blabadi/react-nutracker

Series Parts


Istio —simple fast way to start

istio archeticture (source istio.io) I would like to share with you a sample repo to start and help you continue your jou...