Skip to content

Instantly share code, notes, and snippets.

@pedronauck
Created February 8, 2017 12:42
Show Gist options
  • Save pedronauck/fa168f832bea48576771e1a5da539870 to your computer and use it in GitHub Desktop.
Save pedronauck/fa168f832bea48576771e1a5da539870 to your computer and use it in GitHub Desktop.
Todo Duck example
import { List, fromJS } from 'immutable';
import { createSelector } from 'reselect';
import { createAction, handleActions } from 'redux-actions';
import { takeLatest, takeEvery, take, fork, put, select } from 'redux-saga/effects';
import * as todos from 'ducks/entities/todos';
/**
* Constants
**/
const BASE_ACTION = 'modules/my-module';
const FETCH_RESOURCES = `${BASE_ACTION}/FETCH_RESOURCES`;
const TOGGLE_ACTIVE = `${BASE_ACTION}/TOGGLE_ACTIVE`;
const SELECT_TODO = `${BASE_ACTION}/SELECT_TODO`;
/**
* Reducer
**/
const initialState = Map({
error: false,
isLoading: false,
showingActive: false,
selectedTodo: null
});
const handler = {
[FETCH_RESOURCES]: (state, { payload }) =>
state
.set('isLoading', true)
.set('error', false),
[TOGGLE_ACTIVE]: (state, { payload }) =>
state
.set('showingActive', !state.get('showingActive'))
[SELECT_TODO]: (state, { payload }) =>
state
.set('selectedTodo', payload),
[`${todos.actions.fetchResponse}`]: (state, { payload, error }) =>
state
.set('isLoading', false)
.set('error', error ? payload.message : null)
};
export default handleAction(handler, initialState);
/**
* Selectors
**/
export const selectedTodoSelector = (state) =>
state.getIn(['modules', 'my-modules', 'selectedTodo']);
export const showingActiveSelector = (state) =>
state.getIn(['modules', 'my-modules', 'showingActive']);
export const getTodosToShow = createSelector(
[todos.todosSelector, todos.getActiveTodos, showingActiveSelector],
(todos, activeTodos, showingActiveSelector) => showingActiveSelector ? activeTodos : todos
);
export const getSelectedTodo = createSelector(
[todos.todosSelector, selectedTodoSelector],
(todos, id) => todos.find(todo => todo.get('id') === id)
);
/**
* Sagas and Actions
**/
export const actions = {
fetchResources: createAction(FETCH_RESOURCES),
selectTodo: createAction(SELECT_TODO),
toggleActive: createAction(TOGGLE_ACTIVE)
};
function* fetchResources() {
yield take(`${todos.actions.fetchResponse}`);
const allTodos = yield select(todos.todosSelector);
const firstTodo = todos.first();
yield put(actions.selectTodo(firstTodo.get('id')));
}
export function* sagas() {
yield [
fork(todos.fetchTodos),
yield takeLatest(actions.fetchResources, fetchResources)
]
}
import { fromJS } from 'immutable';
import { createSelector } from 'reselect';
import { createAction, handleActions } from 'redux-actions';
import { put, call } from 'redux-saga/effects';
import { fetch } from 'utils';
/**
* Constants
**/
const BASE_ACTION = 'ducks/entities/todos';
const FETCH_RESPONSE = `${BASE_ACTION}/FETCH_RESPONSE`;
/**
* Reducer
**/
const initialState = List();
const handles = {
[FETCH_RESPONSE]: (state, { payload, error }) => !error ? List(payload) : state
};
export default handleActions(handler, initialState);
/**
* Selectors
**/
export const todosSelector = (state) => state.get('todos');
export const getActiveTodos = createSelector(
[todosSelector],
(todos) => todos.filter(todo => todo.get('active'))
);
/**
* Api
**/
export const api = {
fetchTodos: () => fetch.get('/todos'),
fetchTodo: (id) => fetch.get(`/todos/${id}`)
};
/**
* Sagas and Actions
**/
export const actions = {
fetchResponse: createAction(FETCH_RESPONSE)
};
export function* fetchTodos() {
try {
const { data } = yield call(api.fetchTodos);
yield put(actions.fetchResponse(data));
} catch(error) {
yield put(actions.fetchResponse(new Error(error.message)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment