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. Redux-Thunk
    Radoslav Stankov 26/07/2016

    View Slide

  2. Radoslav Stankov
    @rstankov

    http://rstankov.com

    http://github.com/rstankov

    View Slide

  3. View Slide

  4. View Slide

  5. Reducer
    Action
    React View
    Store

    View Slide

  6. Reducer
    Action
    React View
    New Store

    View Slide

  7. View Slide

  8. class Filters extends React.Component {
    filterHander(filterName) {
    return () => {
    this.props.dispatch(changeFilter(filterName));
    };
    }
    render() {
    return (

    {Object.keys(FILTERS).map((filter) => (

    {filter}

    ))}

    );
    }
    }

    View Slide

  9. function changeFilter(filterName) {
    dispatch({ type: 'TODO/CHANGE_FILTER', filter: filter });
    }

    View Slide

  10. View Slide

  11. View Slide

  12. View Slide

  13. 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 (

    {Object.keys(FILTERS).map((filter) => (

    {filter}

    ))}

    );
    }
    }

    View Slide

  14. View Slide

  15. redux-thunk
    https://github.com/gaearon/redux-thunk

    View Slide

  16. function action() {
    return {
    type: ACTION
    };
    }
    redux-thunk

    View Slide

  17. function action() {
    return async (dispatch, getState) => {
    // do ... async stuff
    dispatch({ type: ACTION_1 });
    // do ... async stuff
    dispatch({ type: ACTION_2 });
    // ...so on
    };
    }
    redux-thunk

    View Slide

  18. import { createStore, applyMiddleware } from 'redux';
    import thunk from 'redux-thunk';
    import reducer from './reducers';
    const store = createStore(rootReducer, applyMiddleware(thunk));

    View Slide

  19. 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 });
    };
    }

    View Slide

  20. this.props.filterChange(filterName, this.props.api);

    View Slide

  21. 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 });
    };
    }

    View Slide

  22. 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));

    View Slide

  23. 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 });
    };
    }

    View Slide

  24. 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 });
    };
    }

    View Slide

  25. class Filters extends React.Component {
    filterHander(filterName) {
    return () => {
    this.props.dispatch(changeFilter(filterName));
    };
    }
    render() {
    return (

    {Object.keys(FILTERS).map((filter) => (

    {filter}

    ))}

    );
    }
    }

    View Slide

  26. 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([]);
    });
    });

    View Slide

  27. View Slide

  28. redux-saga
    https://github.com/yelouafi/redux-saga

    View Slide

  29. redux-saga
    export default function changeFilter(filter) {
    return { type: 'TODO/SET_FILTER', filter: filter };
    }

    View Slide

  30. 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);
    }

    View Slide

  31. 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);

    View Slide

  32. https://speakerdeck.com/rstankov/redux-thunk

    View Slide

  33. View Slide

  34. @rstankov
    Thanks :)

    View Slide