Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Redux-Thunk

 Redux-Thunk

Lightning talk about handling async tasks in redux with redux-thunk.

Radoslav Stankov

July 26, 2016
Tweet

More Decks by Radoslav Stankov

Other Decks in Technology

Transcript

  1. class Filters extends React.Component { filterHander(filterName) { return () =>

    { this.props.dispatch(changeFilter(filterName)); }; } render() { return ( <div> {Object.keys(FILTERS).map((filter) => ( <button key={filter} onClick={this.filterHander(filter)}> {filter} </button> ))} </div> ); } }
  2. class Filters extends React.Component { filterHander(filterName) { return async ()

    => { this.props.dispatch(changeFilter(filterName)); const todos = await this.props.api.loadTodos({filter: filter}); this.props.dispatch(setTodos(todos)); }; } render() { return ( <div> {Object.keys(FILTERS).map((filter) => ( <button key={filter} onClick={this.filterHander(filter)}> {filter} </button> ))} </div> ); } }
  3. function action() { return async (dispatch, getState) => { //

    do ... async stuff dispatch({ type: ACTION_1 }); // do ... async stuff dispatch({ type: ACTION_2 }); // ...so on }; } redux-thunk
  4. import { createStore, applyMiddleware } from 'redux'; import thunk from

    'redux-thunk'; import reducer from './reducers'; const store = createStore(rootReducer, applyMiddleware(thunk));
  5. function changeFilter(filterName, api) { return async function(dispatch, getState) { if

    (getState().filter == filter) { return; } dispatch({ type: 'TODO/LOAD', filter: filter }); const todos = await api.loadTodos({filter: filter}); dispatch({ type: 'TODO/LOADED', todos: todos }); }; }
  6. function changeFilter(filterName, api) { return async function(dispatch, getState) { if

    (getState().filter == filter) { return; } dispatch({ type: 'TODO/LOAD', filter: filter }); const todos = await api.loadTodos({filter: filter}); dispatch({ type: 'TODO/LOADED', todos: todos }); }; }
  7. import { createStore, applyMiddleware } from 'redux'; import thunk from

    'redux-thunk'; import reducer from './reducers'; import apiClient from './utils/apiClient'; const api = apiClient(); const store = createStore(rootReducer, applyMiddleware(thunk.withExtraArgument(api));
  8. function changeFilter(filterName, api) { return async function(dispatch, getState) { if

    (getState().filter == filter) { return; } dispatch({ type: 'TODO/LOAD', filter: filter }); const todos = await api.loadTodos({filter: filter}); dispatch({ type: 'TODO/LOADED', todos: todos }); }; }
  9. function changeFilter(filterName) { return async function(dispatch, getState, api) { if

    (getState().filter == filter) { return; } dispatch({ type: 'TODO/LOAD', filter: filter }); const todos = await api.loadTodos({filter: filter}); dispatch({ type: 'TODO/LOADED', todos: todos }); }; }
  10. class Filters extends React.Component { filterHander(filterName) { return () =>

    { this.props.dispatch(changeFilter(filterName)); }; } render() { return ( <div> {Object.keys(FILTERS).map((filter) => ( <button key={filter} onClick={this.filterHander(filter)}> {filter} </button> ))} </div> ); } }
  11. import createStore from 'tests/support/createStore'; import factory from 'tests/support/factory'; describe(changeFilter.name, ()

    => { it('loads todos', () => { const store = createStore({ filter: 'all' }); const todo = factory.todo(); store.api.stub('loadTodos', [todo]); store.dispatch(changeFilter('completed')); expect(store.getState().filter).to.equal('completed'); expect(store.getState().todos).to.deep.equal([todo]); }); it('does not reload todos when filter is not changing', () => { const store = createStore({ filter: 'all' }); const todo = factory.todo(); store.api.stub('loadTodos', [todo]); store.dispatch(changeFilter('all')); expect(store.getState().todos).to.deep.equal([]); }); });
  12. redux-saga import { takeEvery } from 'redux-saga'; import { put

    } from 'redux-saga/effects'; function* loadFilter(action) { yield put({ type: 'TODO/LOADING' }); const todos = yield api.loadTodos({filter: action.filter}); yield put({ type: 'TODO/LOADED', todos: todos }); } export function* saga() { yield* takeEvery('TODO/SET_FILTER', loadFilter); }
  13. redux-saga import { createStore, applyMiddleware } from 'redux'; import createSagaMiddleware

    from 'redux-saga'; import reducer from './reducers'; import saga from './actions/changeFilter'; const sagaMiddleware = createSagaMiddleware(); const store = createStore(reducer, applyMiddleware(sagaMiddleware)); sagaMiddleware.run(saga);