Skip to main content

[ 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/

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.

Android - Multiple themes for one application

Sometimes you want to have multiple themes for your app
one strong example is having the ability to switch between dark and light themes because during night, a white bright screen can really be annoying for users eyes

Android will do most of the work for you but it may be required to change icons between themes to fit colors
In this blog I'll show a simple app with both dark and light themes and how to change icons without having to do that from code and keep things clean and centralized.
first of all let's create our activity, it will look something like this :


In /rest/values/styles.xml, we inherit Theme.AppCompat
 <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="Theme.AppCompat">
        <!--
            Theme customizations available in newer API levels can go in
            res/values…

Creating your own OAuth2 server and clients using spring security - part 1

In this series of posts, I'll try to put together a simple working example on how to create your own OAuth2 server.

if you want to know more on OAuth2 and when to use it as authentication and authorization protocol then you can search about it on google and i'll put some URLs later.

Now I assume you are familiar with java web applications using Spring and maven.

to get started we need to create the server side with all dependencies required and i'll list them here, i'll use maven 2 to ease downloading dependencies for us.


Steps:

1- Create new maven project with arch type webapp:



2- Add the required depenedencies for spring, spring security, spring-oauth2, hibernate & other libraries (required for this tutorial only you can use other libraries if you like)

https://gist.github.com/anonymous/d33a31ddc3ba84375cf3

3- I used hibernate to automate the creation of the schema required by spring OAuth2 to manage tokens (it's required to have schema created in db if you a…