Redux is a predictable state container for JavaScript apps. That means if you want to use something to manage state of your application you can use Redux. It can work with any modern framework like Vue, React.js or Angular.js. But it more popular with React because of its similarities with Facebooks’s Flux architecture.
Use Redux when:
- When application is getting more complex. Specially with data flows.
- When components need to talk to each other.
- Non Hierarchal data.
- Too many actions from components.
- Same data needed in multiple places.
How Redux works with React.js :
- React: A user action like clicking on submit button dispatches an action.
- Action: Perform the action which is asked (it can be call to webservice to fetch date or something else). As soon as this action is completed it notifies reducer to change it state.
- Reducers: Takes the current state and action and returns a new state. (I know this sounds complicated but its not)
- Store: Notifies other connected components about this state change.
- React-Redux: New data is passed on to these components from store. Now react intelligently determine if UI need to be updated.
- React: If react determines updated is needed in UI. New data is passed via prop from the store and UI re-renders.
Key Components in Redux:
Actions:
Actions are used to transporting data from UI to store. You can use store.dispatch() to send data from UI to store. Action are plain javascript objects which must have a type property indicating type of action that needs to be performed.
Example: You can view full file here
export function createCourseSuccess(course) { return {type: types.CREATE_COURSE_SUCCESS, course}; }
Action can be also used for calling a web-service or call to database or any computation logic.
Example:
Call the actions directly from UI or when your application using dispatch like this :
store.dispatch(loadCourses());
export function loadCourses() { return function(dispatch) { dispatch(beginAjaxCall()); return courseApi.getAllCourses().then(courses => { dispatch(loadCoursesSuccess(courses)); }).catch(error => { throw(error); }); }; }
export function loadCoursesSuccess(courses) { return { type: types.LOAD_COURSES_SUCCESS, courses}; }
Reducers
Reducers are used for changing the state of the application. They take action as state as input and return new state.
For example: You can view the full file here.
export default function courseReducer(state = initialState.courses, action) { switch (action.type) { case types.CREATE_COURSE_SUCCESS: return [ ...state, Object.assign({}, action.course) ]; default: return state; } }
Object.assign is new way in ES6 to make deep copy of object. Read more here.
Store:
Store is the single source of truth for your application. It holds the state of the application.
- Allows access to state via
getState()
; - Allows state to be updated via
dispatch(action)
; (this is the key) - Registers listeners via
subscribe(listener)
; - Handles unregistering of listeners via the function returned by
subscribe(listener)
.
Example: You can view the full code here.
This is the boilerplate code to glue reducers and initial state together.
export default function configureStore(initialState) { return createStore( rootReducer, initialState, applyMiddleware(thunk, reduxImmutableStateInvariant()) ); }
Use dispatch action (Link to source code) :
const store = configureStore(); store.dispatch(loadCourses()); store.dispatch(loadAuthors()); render( <Provider store={store}> <Router history={browserHistory} routes={routes} /> </Provider>, document.getElementById('app') );
Connect:
Connect is a library that connect react components to redux store.
Link to source code:
import {connect} from 'react-redux'; function mapStateToProps(state, ownProps) { return { courses: state.courses }; } function mapDispatchToProps(dispatch) { return { actions: bindActionCreators(courseActions, dispatch) }; } export default connect(mapStateToProps, mapDispatchToProps)(CoursesPage);
[mapStateToProps(state, [ownProps]): stateProps
] (Function): If specified, the component will subscribe to Redux store updates. Any time it updates, mapStateToProps
will be called. Its result must be a plain object*, and it will be merged into the component’s props. If you omit it, the component will not be subscribed to the Redux store.
If ownProps
is specified as a second argument, its value will be the props passed to your component, and mapStateToProps
will be additionally re-invoked whenever the component receives new props (e.g. if props received from a parent component have shallowly changed, and you use the ownProps argument, mapStateToProps is re-evaluated).
[mapDispatchToProps(dispatch, [ownProps]): dispatchProps
] (Object or Function): If an object is passed, each function inside it will be assumed to be a Redux action creator. An object with the same function names, but with every action creator wrapped into a dispatch
call so they may be invoked directly, will be merged into the component’s props. If a function is passed, it will be given dispatch
. It’s up to you to return an object that somehow uses dispatch
to bind action creators in your own way. (Tip: you may use the bindActionCreators()
helper from Redux.) If you omit it, the default implementation just injects dispatch
into your component’s props. If ownProps
is specified as a second argument, its value will be the props passed to your component, and mapDispatchToProps
will be re-invoked whenever the component receives new props.
Full React-Redux project is available here.
References:
https://github.com/reactjs/react-redux
Cory House http://www.reactjsconsulting.com/