workshop 20: reactjs part ii flux pattern & redux

19
Front End Workshops ReactJS - Part II Flux Pattern & Redux Cristina Hernández Jordi Serra

Upload: visual-engineering

Post on 14-Jan-2017

321 views

Category:

Software


1 download

TRANSCRIPT

Front End WorkshopsReactJS - Part II

Flux Pattern & Redux

Cristina Hernández Jordi Serra

ReactJS Summary

1. Decompose UI into reusable components which render to virtual DOM

2. ReactJS will sync VDOM to real browser DOM

3. JSX format

4. Can render on client and server

ReactJS Summary - Component Types

const ButtonChange = ({update}) => { return ( <button onClick={update}> change </button> )}

class Lannister extends React.Component{ constructor(props) {

super(props); this.state = { motto: "Hear me roar" }; } render() { return ( <div> <h3>Lannister</h3> name: {this.props.name} <br/> motto: {this.state.motto} <br/> </div> ); }}

Flux Pattern

Redux Framework

Predictable state container for JS apps

Redux Flow

Redux - Three Principles

1. Single Source of TruthThe whole application must be described solely using a single object: state

2. State is Read-onlyThe only way to change state is to emit an action

3. Changes are made with Pure FunctionsReducers are pure functions → No other variables involved (in or out)All actions pass through all reducers → ensure state is consistent

IN STATE WE TRUST

State: Single Source of Truth

$> console.log(store.getState())

{ visibilityFilter: 'SHOW_ALL', todos: [ { text: 'Consider using Redux', completed: true, }, { text: 'Keep all state in a single tree', completed: false } ]}

State is read only

The only way to mutate the stateis to dispatch an action → an objectdescribing what happened

store.dispatch({ type: 'COMPLETE_TODO', index: 1})

store.dispatch({ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_COMPLETED'})

State after action

State before action

Changes are made with REDUCERS

Reducers are pure functions.Actions pass through all reducersNever mutate state. Always return a new one

import { combineReducers, createStore

} from 'redux'

let reducer = combineReducers({ visibilityFilter, todos })

let store = createStore(reducer)

Changes are made with REDUCERS

function todos(state = [], action) { switch (action.type) { case 'ADD_TODO': return [...state, { text: action.text, completed: false }]

case 'COMPLETE_TODO': return state.map((todo, index) => { if (index === action.index) { return Object.assign({}, todo, { completed: true }) } return todo }) default: return state }}

function visibilityFilter(state =

'SHOW_ALL', action) {

switch (action.type) {

case 'SET_VISIBILITY_FILTER':

return action.filter

default:

return state

}

}

Minions App

Connect React with Redux - mapStateToProps

import React, { Component } from 'react';import { connect } from 'react-redux';

class MinionList extends Component {createMinionMap() {

return this.props.minionList.map(minion => {return (<MinionItem key={minion.id} minion={minion} />);

});}render() {

return (<ul className="col-md-10">{this.createMinionMap()}</ul>);}

}

function mapStateToProps(state) {return {

minionList: state.minionList}

}

export default connect(mapStateToProps)(MinionList);

containers/minion_list.js

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]) - React-redux

Connects a React component to a Redux store.It does not modify the component class passed to it. Instead, it returns a new, connected component class, for you to use.

Connect React with Redux - Dispatch Action

import React, { Component } from 'react';import { connect } from 'react-redux';import { bindActionCreators } from 'redux';import { searchMinion } from '../actions/index';

class SearchBar extends Component {render() {

return ( <div>

<input onChange={event => this.onInputChange(event.target.value)} /> </div>);

}onInputChange(term) {

this.props.searchMinion(term);}

}function mapDispatchToProps(dispatch) {

return bindActionCreators({ searchMinion }, dispatch);}

export default connect(null, mapDispatchToProps)(SearchBar);

containers/search_bar.js

bindActionCreators(actionCreators, dispatch) - Redux

Turns an object whose values are action creators, into an object with the same keys, but with every action creator wrapped into a dispatch call so they may be invoked directly.

Connect React with Redux - Define Action

export const SEARCH_ACTION = 'SEARCH_ACTION';

actions/types.js

import { SEARCH_ACTION } from '../actions/types';

export default function(state=[], action) { switch (action.type) { case SEARCH_ACTION: //return [action.payload, ...state]; return action.payload; default: return state; }}

reducers/minion_search.js

import { SEARCH_ACTION } from './types';

export function searchMinion(term) { return { type: SEARCH_ACTION, payload: getMinionListByTerm(term) }}

actions/index.js

Connect React with Redux - Make store connectable

import React from 'react';import ReactDOM from 'react-dom';import { Provider } from 'react-redux';import { createStore } from 'redux';

import App from './components/app';import rootReducer from './reducers';

ReactDOM.render( <Provider store={createStore(rootReducer)}> <App /> </Provider> , document.querySelector('.container'));

index.js

import { combineReducers } from 'redux';import minionList from './minion_search';import minionSelect from './minion_select';

const rootReducer = combineReducers({ minionList: minionList, //minionList minionSelect: minionSelect //minionSelect});

export default rootReducer;

reducers/index.js

<Provider store> - React-redux

Makes the Redux store available to the connect() calls in the component hierarchy below.

Connect React with Redux - Make store connectable

import React from 'react';import ReactDOM from 'react-dom';import { Provider } from 'react-redux';import { createStore } from 'redux';

import App from './components/app';import rootReducer from './reducers';

ReactDOM.render( <Provider store={createStore(rootReducer)}> <App /> </Provider> , document.querySelector('.container'));

index.js

import { combineReducers } from 'redux';import minionList from './minion_search';import minionSelect from './minion_select';

const rootReducer = combineReducers({ minionList: minionList, //minionList minionSelect: minionSelect //minionSelect});

export default rootReducer;

reducers/index.js

createStore(reducer, [initialState], [enhancer]) - Redux

Creates a Redux store that holds the complete state tree of your app.There should only be a single store in your app.

Connect React with Redux - Make store connectable

import React from 'react';import ReactDOM from 'react-dom';import { Provider } from 'react-redux';import { createStore } from 'redux';

import App from './components/app';import rootReducer from './reducers';

ReactDOM.render( <Provider store={createStore(rootReducer)}> <App /> </Provider> , document.querySelector('.container'));

index.js

import { combineReducers } from 'redux';import minionList from './minion_search';import minionSelect from './minion_select';

const rootReducer = combineReducers({ minionList: minionList, //minionList minionSelect: minionSelect //minionSelect});

export default rootReducer;

reducers/index.js

combineReducers(reducers) - Redux

The combineReducers helper function turns an object whose values are different reducing functions into a single reducing function you can pass to createStore.