What is React Native & Redux
Adopting React Native & Redux instead of MVC
During early project planning phase for any mobile application one of the key questions normally raised is: What language do we use and which frameworks? The purpose of the next few paragraphs is to help anybody reading this transition from “thinking in MVC” to “thinking in Redux” and provide insights in this topic.
Why Developers Love React Native over iOS and Android application Development?
Achieving a mobile app that runs faster, with content that loads quicker therefor users get more time to interact with functionality, smooth animations and feedback make the app enjoyable to use. In emerging markets, where 2011 class phones on 2G networks are the majority, a focus on performance can make the difference between an app that is usable and one that isn't.
Apps that are developed using React Native can be deployed on both the platform, iOS and Android. Individual application development for iOS and Android is quite expensive and in the technological terms the language is itself quite different, together with varying ways for invoking each underlying API function calls and the relevant expected in/out parameters – the way you will require to make network calls is different- the way you use GPS is different and the way you create a GPS object is also different and so on and so forth...
React Native is widely adopted by web developers as it lets them get into mobile app development with a comfortable learning curve based on existing web technology skill sets. Its architecture and tooling is also familiar, as an example Chrome can be used for debugging and there is also notion of a DOM.
What’s Easier: React Native or iOS/Android?
Obviously, it is easier to learn and easier to debug in the comparison to Objective-C, Java or Swift. Another favorable thing is React comes at a cost. JavaScript is not a strict language as many errors can be hidden inside the code. On the other hand, Objective-C/Swift/Java are strict languages as they have a notion of compile time type-checking that eliminates potential errors before you run your code.
Swift is modern language and both objective-C as well as Java continue to get modernized and are not lacking at all in terms of performance and modern language feature. Nevertheless, JavaScript has several well-publicized deficiencies that anyone can google and find an answer. So, React Native is easier to learn.
How React Native Is Soon Going to Take over the Native App Development?
React Native wields the components written in Java, object-C and swift to develop a hybrid application with the unique functionality. Earlier the entrepreneurs were not in favour of hybrid apps due to its highly functional native components. However, with the introduction of React Native, it is now possible to integrate these native components to develop a hybrid application.
Earlier Facebook has offered the support for React Native iOS Development. However, recently, React Native has started to support Android operating system. A new library that can render mobile UIs for both the platforms.
Why Is React Native The Future Of Hybrid App Development?
Considering the overall experience, React Native provides the best output combining the qualities of both hybrid and native frameworks. As it offers the performance attribute of native mobile application and ease of development of the hybrid app.
React-Native and Redux?
As soon as you start learning about react-native (or react), the typical location for obtaining good reading is stack overflow.
So with React Native you must understand firstly the concept of state vs props, you know what componentDidMount does and you even understand how to properly create your components so they are re-usable. Now all of a sudden you found yourself on egghead.io, and some guy is talking about stores, reducer compositions, actions and mapping state to props.
You also realize that while before you were able to do:
$(“.my-button”).click();
to get a button to do something but this one button doesn’t do anything.
Some Analogies
If you are coming from an MVC (or MVVC) world, you are used to models, views and controllers (duh). However in Redux we are dealing with actions, reducers, stores and components. Trying to “translate” MVC to Redux is tricky but here is how I would do it:
Actions = Controller. Think of your actions as the controller. Whenever you want something to happen in your app (i.e. load some data, change a isLoading flag from true to false…) you will have to dispatch an action. Just like in MVC where you would have to call a controller endpoint.
Reducer = Model. Sort of. Your reducers will be in charge of holding the current state of your application (i.e. user info, information loaded from the api, items you want to display…). It will also be the part that decides what to do when an action is called. While in MVC you might have a model with the method setName(), with Redux you would have a reducer handle an action to set the name in the state.
Edit thanks to Prabin Varma. This explains the Store much better.
Stores = ???. The store is Redux specific and doesn’t really have an equivalent in MVC. Not to worry though. This part is taken care off behind the scenes. The store is like a container for the state that aggregates all of the reducers. It has a method to the get the current state, and exposes ways to subscribe to the state changes (using the “connect()” method). This is what will allow you to call actions and pass them in as props to your components.
Components = Views. Components are kind of like your smart views. They display the information that they get from the state. I recommend splitting up your components into two parts. One just for the presentational part (dumb components) and one to handle all of the actions and state changes (smart components).
Moving From MVC Thinking to Redux Thinking
One of the main differences between MVC and Redux is that, while in MVC data can flow in a bidirectional manner, in Redux it strictly moves in one direction.
As you can see (and know from experience) in the diagram above data can flow two ways. You press a button in your view, it sends a message to the controller and that updates the model. The model changes some value, returns the value to the controller, and the controller refreshes the view and voila!
With Redux things work a little differently. Let’s say you have a component and you want to do something when a button gets pressed.
Where do you start?:
- Define your Action
- Define your Reducer
- Define the Actions as a Prop in your Component
- Wire it up in your View
Here is a simple code example to explain these concepts. In this example I will show how to edit a text input and when a user presses a button it will call an action to save it.
First let’s start with the Action file.
export const MODIFY_NAME = "MODIFY_NAME";
export const SAVE_NAME = "SAVE_NAME";
/**
* This is the action we will call from our component whenever the user presses a button. Literally every letter that they will type, this action will be called with the new value in the text input field. Pay attention to the type and payload in this function. This is what we will use in the reducer to "modify" our model with the new values.
**/
export function modifyName(name){
return {
type: MODIFY_NAME,
payload:{
name
}
}
}
/**
This is the action we will call when the user presses the save name button. Notice how we don't pass any value in. That is because the reducer already holds that value. Also there is no payload. The reason for that is the reducer doesn't need one. There is no extra information needed for the reducer step.
Also, normally this would call an api endpoint and all that jazz, but for brevity's sake I won't include that.
**/
export function saveName(){
return {
type: SAVE_NAME
}
}
Now onto our Reducer. Basically, the reducer has to handle the actions that come in.
//import the actions file we defined earlier
import * as constants from '../actions.js';
/**
The initial state is used to define your reducer. Usually you would just set this to default values and empty strings. The reason this is needed is so that when using these values you are guaranteed to at least have some default value. Think of it as the default constructor.
**/
const initialState = {
name:'',
isSaved: false
}
/**
This action part is the part that will "listen" for emitted actions. So the saveName and modifyName functions that we defined earlier will be handled in here. The action parameter is what is being returned (the type and payload) in the functions above.
**/
function name(state=initialState,action){
switch (action.type){
/**
in REDUX the state is immutable. You must always return a new one, which is why use the ES6 spread operator to copy the values from the states that's passed in.
**/case constants.MODIFY_NAME:
return {
...state,
name:action.payload.name
}
case constants.SAVE_NAME:
return {
...state,
isSaved:!state.isSaved
}
}
}
export default name;
Notice how the constants.MODIFY_NAME and constants.SAVE_NAME are exactly what is being returned by our actions in the type field. That is how you let the reducer know what action is happening.
Now to define our “smart” component. Really all this means is this is the component that will define the call to the actions.
/**
* The home page for the app
*/
‘use strict’;
import React, { Component } from ‘react’;
import { connect } from ‘react-redux’;
import Name from ‘./presentational/Name’;
import * as actions from ‘./actions/name’;
/**
Both the actual values (name and isSaved) as well as the function to call those actions are passed in as props.**/
class NameContainer extends Component {
render() {
return (
<Name
name = {this.props.name}
isSaved = {this.props.isSaved}
modifyName = {this.props.modifyName}
saveName = {this.props.saveName}
/>
);
}
}
/**
All this does is get the values that are saved in the reducer, and return it to the component so that we can call them using this.props
**/
const mapStateToProps = (state,ownProps) =>{
/**
using REDUX stores, it allows us to just access the reducer values by going state.name. Notice how name is what is being exported in the reducer above
**/
const { name, isSaved } = state.name;
return {name,isSaved };
}
/**
In mapStateToProps we were mapping the state variables as properties to pass into our presentational component. In mapDispatchToProps we are mapping the action functions to our container to be able to pass it into our presentational component.
**/
const mapDispatchToProps = (dispatch) => {
return {
modifyName:(name)=>{
dispatch(actions.modifyName(name))
},
saveName:()=>{
dispatch(actions.saveName())
},
}
/**
This is the reason we are able to pass in the functions and variables as props to our container. It's the connect function from the react-redux library that does all the magic.
**/
export default connect(mapStateToProps,mapDispatchToProps)(NameContainer);
Now for the easiest part. You create your presentational component that the user will interact with (the V in MVC).
/**
* the dumb component which will use the props passed in from the smart component based on a user's actions
*/
‘use strict’;
import React, { Component } from ‘react’;
import {Text,TextInput, TouchableOpacity} from ‘react-native’;
import { Actions, ActionConst } from ‘react-native-router-flux’;
class Name extends Component
render() {
return (
<View>
<TextInput
multiline={false}
//from the component above
value={this.props.name}
placeholder=”Full Name”
//from the component above
onChangeText ?={(name)=>this.props.modifyName(name)}
/>
<TouchableOpacity onPress ?= {()=>{this.props.saveName()}>
<Text>Save</Text>
</TouchableOpacity>
</View>
);
}
}
export default Name;
And that’s it! You still have to do some basic boilerplate setup stuff, hopefully this clears up how to think in redux.