React-Redux for Ruby On Rails developers

We have saw how to develop our first React component. But, as always happens, the HelloWorld example doesn’t reflex a real life situation. Typically in a real application React components communicate among them in a way more complex than the simple Parent->Child situation, and also, they consume an API. This is why we need Redux, a Predictable State Container.

The main concepts around Redux are: actions, reducers, store, provider and dispatch.

Reducer: The key concept in Redux (as you must suspect) is the idea behind the “reducers”. A reducer is a small and simple JavaScript function that normally contains a switch statement in it. The typical reducer is small and simple because its duty is small and simple: it just changes the state, nothing else. Think about a reducer like the electrical switch in your wall: it just changes the state from Off to On when you push it.

Store: the store is a variable that contains two things: the Redux API and your reducers.

Provider: it takes the Store variable and your react project and connect them. Store and Provider are variables that are setup one time in your index.jsx file, they connect React with Redux but you don’t use them directly.

Action: as reducers, actions are just JavaScript functions, but they process the data and pass the result to the reducer. Actions are executed after dispatch() and before that the reducer. In some way, Actions are similar to RoR models, in the way that they are the place where most of the “action” happens.

Dispatch: this is a simple Redux function that is used to trigger an Action from a React class.

This a simple and unidirectional process:

  1. The user clicks in a button that executes dispatch(Action) inside the React component.
  2. Action do its thing (call an API or calculate a TAX revenue or whatever)
  3. The result of the Action is passed to the reducer which changes the state
  4. The React Component now can use the data in the this.props variable.

Enough of talking. We need to be in our REACT_HOME dir and then install what we need:

npm i --save redux react-redux redux-logger

Create new dirs:

mkdir reducers
mkdir actions

Our first reducer:

// file: reducers/my_reducer.jsx
import { JUST_COUNT } from ‘../actions/my_actions’
const initialState = {
myCounter: 0
}
export default function myRdcr(state = initialState, action){
switch (action.type) {
case JUST_COUNT:
return Object.assign({}, state, {
myCounter: action.myCounter
})
default:
return state
}
}

Usually the reducers are loaded and combined in an index.jsx file:

// file: reducers/index.js
import { combineReducers } from ‘redux’
import myRdcr from ‘./my_reducer’
const myApp = combineReducers({
myRdcr
})
export default myApp

The action that will be dispatched:

// file: actions/my_actions.jsx
export const JUST_COUNT = ‘JUST_COUNT’;
export function doCount(number) {
let new_number = number + 1;
return {
type: JUST_COUNT,
myCounter: new_number
}
}

We need to create a Redux store and put it inside a Provider. The Provider is a Redux component that makes the Redux store available to the connect() calls:

// file: index.jsx
import ‘babel-polyfill’
import React from ‘react’
import { render } from ‘react-dom’
import { Provider } from ‘react-redux’
import { createStore, applyMiddleware, compose } from ‘redux’
import thunkMiddleware from ‘redux-thunk’
import createLogger from ‘redux-logger’;
import myApp from ‘./reducers/index’
import App from ‘./App’
const store = createStore(myApp,
applyMiddleware(thunkMiddleware, createLogger())
)
// Provider wraps React into Redux
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById(‘react_entry’)
)

Finally, our React Component:

// file: App.jsx
import React, { Component, PropTypes } from ‘react’
import { render } from ‘react-dom’
import { connect } from ‘react-redux’
import * as ActionCreators from ‘./actions/my_actions’
class App extends Component {
constructor(props) {
super(props);
this.state = {
salute: ‘Hello (Virtual DOM) World !!!’,
countries: [{name: ‘Argentina:’, capital:’Buenos Aires’},
{name: ‘Peru’, capital:’Lima’},
{name: ‘Uruguay’, capital:’Montevideo’}]
}
this.handleClick = this.handleClick.bind(this); // linking the method scope
this.addOne = this.addOne.bind(this);
}
handleClick(){
this.setState({salute: ‘Hey, a new salute!’})
}
addOne(){
let action = ActionCreators.doCount(this.props.counter)
this.props.dispatch(action)
}
render() {
return (
<div>
<h2>{this.state.salute}</h2>
{ this.state.countries.map((object, i) => {
return <div key={i}> Country: <b>{object.name}</b> and capital: <b>{object.capital}</b> </div>
})}
<p id=”onclick”><button onClick={this.handleClick}>Change title</button></p>
<p id=”onclick”><button onClick={this.addOne}>Add One</button></p>
<div> {this.props.counter}</div>
</div>
)
}
}
App.propTypes = {
counter: PropTypes.number
}
App.defaultProps = {
counter: 0
}
const mapStateToProps = (state) => {
return {
counter: state.myRdcr.myCounter // link local props with the store
}
}
export default connect(mapStateToProps)(App)

Now when you click the “Add One” button you must see the how the reducer changes the state:

So, to recapitulate the data flow:

1). We create a reducer function that will change the state

2).We load the reducers inside a store

3).Pass the store to the Provider and then wrap our React App with this Provider:

<Provider store={store}>
<App />
</Provider>

4).Connect React with Redux using the connect Redux method:

export default connect(mapStateToProps)(App)

5). Load the actions inside the React Component

6). Call that action with the dispatch Redux method:

 let action = ActionCreators.doCount(this.props.counter)
this.props.dispatch(action)

7). The action will be executed and the result will be passed to the component

8). The line:

counter: state.myRdcr.myCounter

links the local this.props.counter variable with the result of the myRdcr reducer function.

And now you know how Redux change the this.props var in a React class.

Final observations about Redux:

  • It’s a “wrapper” around all our components (id est, it wires our React classes)
  • It puts a store variable in our environment and we can access that store using the this.state var inside our React classes
  • The Redux store contains a collection of reducers, a reducer is a function that has a unique purpose: to tell to Redux how to change the state
  • A reducer is called after that an Action (another simple javascript function) is executed
  • Actions are triggered by the dispatch() Redux method
  • Since a React component is connected with Redux, the change of the state in the reducer will change the this.props variable in the React component and then we can use the data in our view
One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.