sweet-redux-saga

1.0.5 • Public • Published

Sweet redux saga 😀

Декораторы для react-redux и redux-saga

npm install sweet-redux-saga

##Предпосылки При разработке используя react-redux и redux-saga приходиться писать много однотипного кода, не относящегося к логике приложения. Данная библиотека призвана сократить этот код, и сделать его более понятный и читаемым.

##Как это выглядит ###Фабрика событий (actionsСreator) до:

const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
const DECREMENT_COUNTER = 'DECREMENT_COUNTER';
const SET_POSITION = 'SET_POSITION';
const CHANGE_USER = 'CHANGE_USER';

export function incrementCounter() {
  return {
    type: INCREMENT_COUNTER,
  };
}

export function decrementCounter() {
  return {
    type: DECREMENT_COUNTER,
  };
}

export function setPosition(x, y) {
  return {
    type: SET_POSITION,
    payload: {
      x,
      y,
    },
  };
}

export function changeUser(userName) {
  return {
    type: CHANGE_USER,
    payload: {
      userName,
    },
  };
}

после:

import { actionsCreator, payload } from 'sweet-redux-saga';

@actionsCreator()
export class myActionsCreator {
  //Если передаваемых параметров нет, можно объявить так
  incrementCounter;

  @payload()
  decrementCounter;

  @payload('x', 'y')
  setPosition;

  @payload('userName')
  changeUser;
}

###Редьюсер (reducer) до:

import { SET_VISIBILITY_FILTER, ADD_TODO } from './constanst';

const initialState = {
  visibilityFilter: null,
  todos: [],
};

export function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.payload.filter,
      });
    case ADD_TODO:
      return Object.assign({}, state, {
        todos: [
          ...state.todos,
          {
            text: action.payload.text,
            completed: false,
          },
        ],
      });
    default:
      return state;
  }
}

после:

import { reducer } from 'sweet-redux-saga';
import { SET_VISIBILITY_FILTER, ADD_TODO } from './constanst';

@reducer({
  visibilityFilter: null,
  todos: [],
})
export class TodoApp {
  [SET_VISIBILITY_FILTER](state, action) {
    return Object.assign({}, state, {
                   visibilityFilter: action.payload.filter
            }}

  [ADD_TODO](state, action) {
    return Object.assign({}, state, {
                   todos: [
                     ...state.todos,
                     {
                       text: action.payload.text,
                       completed: false,
                     },
                   ],
                 });
}

###Саги (sagas) до:

import { put, takeEvery, takeLatest, all, delay } from 'redux-saga/effects';
import {
  INCREMENT_ASYNC,
  DECREMENT_ASYNC,
  INCREMENT,
  DECREMENT,
} from './constants';

function* incrementAsync() {
  yield delay(1000);
  yield put({ type: INCREMENT });
}

function* watchIncrementAsync() {
  yield takeEvery(INCREMENT_ASYNC, incrementAsync);
}

function* decrementAsync() {
  yield delay(1000);
  yield put({ type: DECREMENT });
}

function* watchDecrementAsync() {
  yield takeLatest(DECREMENT_ASYNC, decrementAsync);
}

export default function* rootSaga() {
  yield all([watchIncrementAsync(), watchDecrementAsync()]);
}

после:

import { sagas, takeEvery, takeLatest } from 'sweet-redux-saga';
import {
  INCREMENT_ASYNC,
  DECREMENT_ASYNC,
  INCREMENT,
  DECREMENT,
} from './constants';

@sagas()
export default class RootSaga {
  @takeEvery([INCREMENT_ASYNC])
  *incrementAsync(action) {
    yield delay(1000);
    yield put({ type: INCREMENT });
  }

  @takeLatest([DECREMENT_ASYNC])
  *decrementAsync(action) {
    yield delay(1000);
    yield put({ type: DECREMENT });
  }
}

###Фильтр событий (filterActions) до:

import { put, takeEvery, all, select } from 'redux-saga/effects';
import { INCREMENT_ASYNC, INCREMENT } from './constants';

function* incrementAsync(action) {
  const state = yield select();
  if (action.payload.id !== 10 || state.flag) {
    return;
  }
  yield put({ type: INCREMENT });
}

function* watchIncrementAsync() {
  yield takeEvery(INCREMENT_ASYNC, incrementAsync);
}

export default function* rootSaga() {
  yield all([watchIncrementAsync()]);
}

после:

import { sagas, takeEvery } from 'sweet-redux-saga';
import { INCREMENT_ASYNC, INCREMENT } from './constants';
import { filterActions } from './SagaDecorators';

@sagas()
export default class RootSaga {
  @takeEvery([INCREMENT_ASYNC])
  @filterActions(({ state, payload }) => payload.id === 10 && state.flag)
  *incrementAsync() {
    yield put({ type: INCREMENT });
  }
}

###Обработчик исключений(catchError) до:

import { put, takeEvery, all } from 'redux-saga/effects';
import { getUserSuccess, getUserError } from './userActions';
import { userServive } from './userService';
import { GET_USER_REQUEST } from './constants';

function* getUserWorker(action) {
  try {
    const user = yield userServive.getUser(action.payload.id);
    yield put(getUserSuccess(user));
  } catch (error) {
    yield put(getUserError(error.message));
  }
}

function* getUserWatcher() {
  yield takeEvery(GET_USER_REQUEST, getUserWorker);
}

export default function* rootSaga() {
  yield all([getUserWatcher()]);
}

после:

import { sagas, takeEvery } from 'sweet-redux-saga';
import { getUserSuccess, getUserError } from './userActions';
import { userServive } from './userService';
import { GET_USER_REQUEST } from './constants';
import { catchError } from './SagaDecorators';

@sagas()
export default class RootSaga {
  @takeEvery([GET_USER_REQUEST])
  @catchError(function*(error) {
    yield put(getUserError(error.message));
  })
  *incrementAsync(action) {
    const user = yield userServive.getUser(action.payload.id);
    yield put(getUserSuccess(user));
  }
}

###Конект (connect) до:

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

class Field extends React.Component {
  render() {
    return <div>Some template</div>;
  }
}

export default connect(
  (state, props) => ({}),
  (dispatch, props) => ({})
)(Field);

после:

import React from 'react';
import { connect } from 'sweet-redux-saga';

@connect(
  (state, props) => ({}),
  (dispatch, props) => ({})
)
export default class Field extends React.Component {
  render() {
    return <div>Some template</div>;
  }
}

##Установка ###Инициализация в хранилище (store) store.js

import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducers from './rootReducer';
import rootSagas from './rootSagas';

const sagaMiddleware = createSagaMiddleware();

const middlewares = [sagaMiddleware];

export const store = createStore(rootReducers, applyMiddleware(...middlewares));

sagaMiddleware.run(rootSagas);

rootReducer.js

import { combineReducers } from 'redux';
import TodoReduces from './TodoReduces';

export function rootReducers() {
  return combineReducers({
    todo: new TodoReduces(),
  });
}

rootSagas.js

import { all } from 'redux-saga/effects';
import TodoSagas from './TodoSagas';

export function* rootSagas() {
  yield all([new TodoSagas()]);
}

Создание фабрики событий

TodoActions.js

@actionsCreator()
class TodoActions {
  @payload('id')
  setId;

  @payload('text')
  setText;
}

export const todoActions = new TodoActions();

###Создание редьюсера TodoReduces.js

import { reducer } from 'sweet-redux-saga';
import { todoActions } from 'TodoActions';

@reducer({
  id: null,
  text: null,
})
export default class TodoReducer {
  [todoActions.setId](state, { payload }) {
    return {
      ...state,
      id: payload.id,
    };
  }

  [todoActions.setText](state, { payload }) {
    return {
      ...state,
      text: payload.text,
    };
  }
}

###Создание саги TodoSagas.js

import { put } from 'redux-saga/effects';
import { sagas, takeEvery, takeLatest } from 'sweet-redux-saga';
import { todoActions } from 'TodoActions';

@sagas()
export default class TodoSagas {
  @takeLatest([todoActions.setId])
  *setId({ payload }) {
    if (payload.id === 13) {
      yield put(todoActions.setText('Плохой id, давайте поменяем'));
    }
  }

  @takeEvery([todoActions.setText])
  *logChangeText({ payload }) {
    console.log(payload.text);
  }
}

Dependents (0)

Package Sidebar

Install

npm i sweet-redux-saga

Weekly Downloads

1

Version

1.0.5

License

MIT

Unpacked Size

177 kB

Total Files

15

Last publish

Collaborators

  • dmitryorelopt