Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Building React Applications with Redux

1,733 views

Published on

Building React Applications with Redux
with Yuri Takhteyev

OVERVIEW

Since React is just a “view framework”, it leaves you with lots of options for how to architect the deeper parts of your stack. The best way to handle those deeper layers is by using Redux – a state container that allows you to write much of your application in the form of pure functions. Using Redux helps you write applications that are much easier to test and understand and to achieve more thorough separation between your views and your business logic. Redux also unlocks the possibility of using amazing tools.

OBJECTIVE

Introduce the audience to Redux, a state container that can be used together with React to achieve sanity deeper down in your stack.

TARGET AUDIENCE

Developers familiar with core React and looking for a better way to architect their applications.

ASSUMED AUDIENCE KNOWLEDGE

Core React knowledge is assumed. Familiarity with basic Flux concepts would help, but I’ll review those quickly.

FIVE THINGS AUDIENCE MEMBERS WILL LEARN

Why pure functions make your code easier to maintain.
How unidirectional data flows help you sleep better at night.
How Redux helps you manage state better via reducers.
How to use Redux together with React.
How to test Redux applications.

Published in: Internet

Building React Applications with Redux

  1. 1. Image by mulad Many people choose to think of React as the V in MVC. – “Why React?” in React documentation “
  2. 2. MVC in Theory Image by mulad Model( ͡° ͜ʖ ͡°) View Controller
  3. 3. MVC in Practice Image by mulad View Model Model Model Model Model View Model View Model View Model ಠ_ಠ
  4. 4. Isolated (“Dumb”) Components Parent Child Props Callbacks Maximize your use of “dumb” components.
  5. 5. Advantages of Isolated Components • Helps with code reuse. • Helps with testing. • Makes it easy to reason about your code. Image by mulad
  6. 6. Sources of Those Benefits • Dumb components are isolation from the rest of the application. • Dumb components are mostly stateless. Image by mulad
  7. 7. Trouble with State • A lot of us were raised on OOP. Objects are stateful. • The effect of calling a method depends on the arguments and the object’s state. • Very painful to test. • Very hard to understand. • Aims to mimic the real world. • But why replicate the unnecessary complexity? Image by mulad
  8. 8. Alternative: Pure Functions • The output of a pure function depends only on inputs. • Pure function has no side-effects. • Much easier to understand. • Much easier to test. • Very easy to build through composition. Image by mulad
  9. 9. Truly Stateless Components Image by mulad function HelloMessage(props) { return <div>Hello {props.name}</div>; }
  10. 10. Even Better Image by mulad const HelloMessage = (props) => <div>Hello {props.name}</div>; Use stateless components whenever you can.
  11. 11. Where Does Business Logic Go? • Each component gets props from its parent. • Each component transmits actions to the parent. • Turtles all the way down up? • Top-level components need to be a bit smarter! • We’ll call them “container components”. Image by mulad
  12. 12. Linking Containers with Models Image by mulad Container Model ModelContainer Nevermind…
  13. 13. Should We Use the Container’s State? • We could, but so much for separation of concerns… Image by mulad
  14. 14. What If We Did It the React Way? ??? Container Component Props Callbacks
  15. 15. What If We Did It the React Way? State Container Container Component Props Callbacks
  16. 16. Flux Architecture State Container Container Component Change events Actions
  17. 17. Handling Data in the State Container Component StoreComponent Dispatcher Action
  18. 18. Handling Data in the State Container Component Store API, etc. Component Dispatcher Action(s)Action
 Creator We’ll see another
 way of doing this.
  19. 19. Redux
  20. 20. A Better State Container • https://github.com/rackt/redux • Pretty much the dominant way of doing Flux with React today. • Key concepts: a single store + state “reducers”. • Can a single store be a good idea? • What the heck is a “reducer”?
  21. 21. Reducer Functions • Basic reduce(): function addOneValue (value, state) { return state + value; } [1,2,3,4,5].reduce(addOneValue, 0); • Running through the items: 1: 0 => 1 2: 1 => 3 3: 3 => 6 4: 6 => 10 5: 10 => 15
  22. 22. Action Reducers in Redux • Take an action and a state, return a new state. • Your app’s state is a reduction over the actions. • Each reducer operates on a subset of the global state. • Simple reducers are combined into complex ones.
  23. 23. Creating an Action const UPDATE_NOTE_CONTENT = 'App/UPDATE_NOTE_CONTENT'; function updateNoteContent(noteId, newContent) { return { type: UPDATE_NOTE_CONTENT, payload: { noteId: noteId, newContent: newContent } } }
  24. 24. Creating an Action, more ES6 const UPDATE_NOTE_CONTENT = 'App/UPDATE_NOTE_CONTENT'; const updateNoteContent = (noteId, newContent) => ({ type: UPDATE_NOTE_CONTENT, payload: {noteId, newContent} });
  25. 25. A Reducer export const notes = createReducer({ [UPDATE_NOTE_CONTENT]: (state, action) => state.setIn( ['byId', action.payload.noteId, 'html'], action.payload.newContent ), [SOME_OTHER_ACTION]: (state, action) => { // do something else or just return state; }), });
  26. 26. A Reducer, more ES5ish export const notes = createReducer({ [UPDATE_NOTE_CONTENT]: function (state, action) { return state.setIn( ['byId', action.payload.noteId, 'html'], action.payload.newContent ); }, [SOME_OTHER_ACTION]: function (state, action) { // do something else or just return state; }, });
  27. 27. Why Is This a Good Idea? • Reducers are pure functions – easy to understand, easy to test. • Reducers are synchronous. • Data logic is 100% separated from view logic. • You can still have modularity by combining reducers. • New opportunities for tools.
  28. 28. How Do We Avoid Mutating State? • Reducers are supposed to not change the old state. But how do we keep them honest? • One option is to clone the object every time. • “Immutable.JS” is the library to use. var newData = data.setIn( ['foo', 'bar', 'baz'], 42 ); • This is a key building block for stateless architecture.
  29. 29. The Reducer Example Again export const notes = createReducer({ [UPDATE_NOTE_CONTENT]: (state, action) => state.setIn( ['byId', action.payload.noteId, 'html'], action.payload.newContent ), [SOME_OTHER_ACTION]: (state, action) => { // do something else or just return state; }), });
  30. 30. Connecting Container Components import { connect } from 'react-redux'; export default connect( mapStateToProps, mapDispatchToProps, )(MainPage);
  31. 31. React-Redux Mapping Functions function mapStateToProps(state) { const notesAsJS = state.notes.toJS(); return { notes: notesAsJS.ordered.map((id) => notesAsJS.byId[id]) }; } function mapDispatchToProps(dispatch) { return { onContentChange: (noteId, newContent) => dispatch(noteActions.updateNoteContent( noteId, newContent)), }; }
  32. 32. Handling Asyncronous Actions • Option 1: “Smart” actions creators. • Option 2: Middleware. • Option 2′: React Sagas.
  33. 33. Smart Action Creators • Call an action creator to initiate a request. • The action creator emits an action to inform everyone that a request was made. • The action creator makes a request. • If the request succeeds, the action creator emits an action to inform everyone that a request was completed. (Same for failure and timeout.) • The details of interacting with the server should be pushed into a module.
  34. 34. An Example, Part 1 function makeFetchNotesAction(status, data) { return { type: FETCH_NOTES, payload: { status: status, data: data } }; }
  35. 35. An Example, Part 1 export function fetchNotes() { return dispatch => { dispatch(makeFetchNotesAction('request')); return fetchData() .then(json => dispatch(makeFetchNotesAction('success', json))) .catch(error => dispatch(makeFetchNotesAction('error', error))); }; }
  36. 36. Alternatively: Redux Middleware • A middleware is a function that allows you to capture actions and do something before they get to the reducers. • This can include things like API calls. • More generally, the sky is the limit. • Perhaps a little too generic for many cases.
  37. 37. Alternative: Redux Sagas • A middleware that works with generators. • Awesome, if you understand generators. • Can simplify complex workflows. • Very new.
  38. 38. Redux Sagas Example function* fetchNotesForStack(action) { const stackId = action.payload.stackId; yield put(getNotes.request()); const {data, error} = yield dataApi.getNotesForStack(stackId); if (!error) { yield put(getNotes.success(organizeNotes(data.notes))); } else { yield put(getNotes.failure(error)); } } function* watchFetchNotesForStack() { yield* takeEvery(SELECT_STACK, fetchNotesForStack); }
  39. 39. Testing Is Easy describe('on ADD_NOTE', () => { it('should create a new note', () => { const getNoteCount = () => initialState.toJS().ordered.length; const previousCount = getNoteCount(); const newState = notesReducer(initialState, {type: ADD_NOTE}); assert.strictEqual(previousCount + 1, getNoteCount()); const newNoteId = newState.toJS().ordered[0]; const newNoteHtml = newState.getIn(['byId', newNoteId, 'html']); assert.strictEqual(newNoteHtml, 'No content'); }); });
  40. 40. Caveats • Its addictive. • You won’t be happy using anything else. • Your friends might not understand your obsession.
  41. 41. THANK YOU! Yuri Takhteyev @qaramazov rangle CTO, Rangle.io Some rights reserved - Creative Commons 2.0 by-sa

×