Как сделать жизнь Redux разработчика проще? -1
Ваш покорный слуга также испытал очень много
И так — после некоторого времени я (master-7) и мой коллега (one-more) попробовали справиться с этим страшным сном фронтэндера и создали весьма интересную библиотечку Redux-Utils.
Конечно же, мы попытались написать общепонятное и исчерпывающее ридми, но для затравки — несколько примеров в статье.
Одна из самых интересных фичей — это объектное создание редюсеров.
import {Reducer} from 'redux-util'
import {UserState} from 'types/UserState'
import {
GET_USER_DATA_REQUEST,
GET_USER_DATA_SUCCESS,
GET_USER_DATA_FAIL
} from 'services/actionTypes'
const initialState: UserState = [];
export default Reducer(initialState, {
[GET_USER_DATA_REQUEST]: () => null,
[GET_USER_DATA_SUCCESS]: (state, action) => ({
...state,
data: action.users
}),
[GET_USER_DATA_FAIL]: (state, action) => ({
...state,
error: action.error
})
});
Как вы можете видеть, код стал намного более читабельным по сравнению с записью вида:
import {Reducer} from 'redux-util'
import {UserState} from 'types/UserState'
import {
GET_USER_DATA_REQUEST,
GET_USER_DATA_SUCCESS,
GET_USER_DATA_FAIL
} from 'services/actionTypes'
const initialState: UserState = [];
export default function Reducer(state = initialState, action) => {
switch (action.type) {
case GET_USER_DATA_REQUEST:
return null;
case GET_USER_DATA_REQUEST:
return {
...state,
data: action.users
};
case GET_USER_DATA_FAIL:
return {
...state,
error: action.error
};
default:
return state;
}
Ну и киллер фича номер два — посмотрим на создание экшенов:
import {buildGenericActionCreator} from 'redux-util'
const START_LOADING = 'START_LOADING';
const END_LOADING = 'END_LOADING';
export const startLoadingActionCreator = buildGenericActionCreator(START_LOADING);
export const endLoadingActionCreator = buildGenericActionCreator(END_LOADING);
// ....
import {startLoadingActionCreator, endLoadingActionCreator} from 'loading-reducer'
const PREFIX = 'PREFIX';
const startLoading = startLoadingActionCreator(PREFIX);
const endLoading = endLoadingActionCreator(PREFIX);
export const loadUser = () => (dispatch: Dispatch) => {
dispatch(startLoading());
return api.fetchUser().then(
response => {
dispatch(
loadUserDataAction(response)
);
dispatch(endLoading());
}
);
};
И еще много интересного вы можете найти в ридми проекта! Надеюсь, данная библиотека сделает вашу работу легче.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Комментарии (20)
xGromMx
24.04.2017 20:03+4Как сделать жизнь Redux разработчика проще? Просто не использовать его
kanstantsin
25.04.2017 20:57Золотые слова. Вспоминаю как страшный сон эти тонны повторяющегося кода. Особенно доставляют константа на константе и спагетти из функций, которые аргументы функций, являющихся аргументами функций и т.д. по схеме. Как будто код какой-нибудь CMS из 2005 года.
xGromMx
25.04.2017 20:58и на что перешли?)
kanstantsin
25.04.2017 21:03Пока mobx, пока ок, если подумать над архитектурой прежде, чем начать писать :) Но кода стало меньше, появилось какое-никакое ООП, typescript опять же сильно помогает, уже почти можно жить :)
xGromMx
25.04.2017 21:12Ну mobx не про ООП =)
kanstantsin
26.04.2017 14:13+1mobx нет, но попытки писать в ооп-стиле с redux это пытка.
justboris
26.04.2017 14:27А зачем обязательно ООП?
Есть и другие способы разбиения проекта на части, о которых написано в документации Redux
raveclassic
25.04.2017 23:18+1Вспоминаю как страшный сон эти тонны повторяющегося кода
А можете пример, что у вас там так повторялось? Быть может, дело в том коде, а не в redux?
Особенно доставляют константа на константе
А что не так с константами?
которые аргументы функций, являющихся аргументами функций и т.д. по схеме
И что не так с ФВП?kanstantsin
26.04.2017 14:19Я не хочу вступать в полемику, просто на проекте в ~25k строк кода со значительным кол-вом запросов к api размер, поддерживаемость, читаемость кода начинают иметь особое значение, поэтому отказ от redux оказался верным решением. На простых примерах типа todo все выглядит прилично, но на реальных проектах появляются проблемы. Только личный опыт :)
raveclassic
26.04.2017 16:09Возможно из-за того, что redux не дает каких-либо внятных рекомендаций по архитектуре сервисного и доменного слоев, предоставляя лишь паттерн для организации внутреннего взаимодействия UI. То, что экшены могут быть thunk'ами или promise'ами — не более чем сильное допущение и упрощение. И когда проект начинает разрастаться, становится понятно, что серьезному IO/эффектам не место ни в редьюсерах, ни в экшенах, ни вообще в redux, так как это не его задача (хоть redux и предоставляет возможность вставки middleware).
Рекомендую посмотреть на redux-saga и redux-observable. Обе решают наболевшую проблему толстых экшенов с кучей копипасты, расширяемости и поддерживаемости. Саги только в качестве бонуса предоставляют тестируемость без каких-либо моков.
comerc
26.04.2017 11:06Вы просто не умеете его готовить. Константы не нужны совсем.
https://github.com/comerc/yobr/blob/master/src/ducks/postForm.js
pinebit
24.04.2017 21:18+1Это уже наверное пятый улучшитель redux за месяц. Право же, не нужны они.
Единственный тул который я сделал сам себе — связка redux action, saga и fetch, чтобы один dispatch запустил сагу, та вызвала API и все декларативно. Думал выложить это на гитхаб, но вовремя остановился.
justboris
И чем ваше решение лучше старого доброго redux-actions?
pinebit
Ну или redux sauce: https://github.com/skellock/reduxsauce
comerc
Есть "гораздо более лучший" вариант — redux-act