Comments 14
Зря не читали! Дальше встречаются такие перлы, как, например этот кусок кода:
export const someReduceLabelActionCreator = FetchSaga.bind(this, SOME_REDUCE_LABEL);
Акшен
import { LocalesApi } from '../api/locales.api';
class Actions {
prefix = 'LOCALES_ACTIONS';
REQUEST = `${this.prefix}_REQUEST`;
SUCCESS = `${this.prefix}_SUCCESS`;
ERROR = `${this.prefix}_ERROR`;
CLEAR = `${this.prefix}_CLEAR`;
request = () => ({
type: this.REQUEST,
})
success = messages => ({
type: this.SUCCESS,
messages,
})
clear = () => ({
type: this.CLEAR,
})
error = error => ({
type: this.ERROR,
error,
})
getByLocale = locale => async dispatch => {
try {
dispatch(this.request());
const result = await LocalesApi.getByLocale(locale);
dispatch(this.success(result));
} catch (error) {
dispatch(this.error(error.message));
}
}
}
export const LocalesActions = new Actions();й
Редюсер
import { LocalesActions } from '../actions/locales.actions';
import { LOCALES } from '../constants/locales.constants';
const initialState = {
shouldInitialize: true,
updating: false,
locale: LOCALES.SUPPORTED[0],
messages: {},
};
export default (state = initialState, action) => {
switch (action.type) {
case LocalesActions.REQUEST:
return {
...state,
shouldInitialize: false,
updating: true,
};
case LocalesActions.SUCCESS:{
const { messages } = action;
return {
...state,
updating: false,
messages,
};
}
case LocalesActions.ERROR:{
const { error } = action;
return {
...state,
updating: false,
error
};
}
default:
return state;
}
};
Использование в контейнере
import { connect } from 'react-redux';
import { IntlProviderComponent } from './IntlProvider.component';
import { STORES } from '../constants/stores.constants';
import { LocalesActions } from '../actions/locales.actions';
const mapStateToProps = state => ({
locales: state[STORES.LOCALES],
});
const mapDispatchToProps = dispatch => ({
getMessages: locale => dispatch(LocalesActions.getByLocale(locale)),
});
export const IntlProvider =
connect(mapStateToProps, mapDispatchToProps)(IntlProviderComponent);
Я делал что-то подобное, но только еще селекторы туда добавил
class TestModule extends DuckModule {
constructor(prefix, rootSelector) {
super(prefix, rootSelector);
//define actions here
this.INC = this.prefix + "INC"; // action name
}
/**
* Create new action of this.INC type
*/
inc(x) {
return {type: this.INC, payload: x}
}
/**
* Selector for X value
* @param state
*/
getX(state) {
return this.getRoot(state).x;
}
reduce(state = {x: 0}, action) {
switch (action.type) {
case this.INC:
return {x: state.x + action.payload};
}
return super.reduce(state, action);
}
}
test("Selectors and actions", () => {
expect(module.getX(state)).toBe(0);
//...
dispatch(module.inc(1));
//...
expect(module.getX(state)).toBe(1);
});
Из минусов, reselect из коробки прицепить сложно (но впринципе можно самомму организовать альтернативу). Хотел сделать новую версию, но пока отошел от занятия фронтом.
https://www.npmjs.com/package/simple-duck — кому интересно, больше примеров (combineModules, использование наследования)
Про страницы — я использовал другой подход, были такие модули отдельно для GUI и для бизнес логики. И например если в каком-то модуле GUI нужно было вывести значение из бизнес-модуля, то грубо говоря так
import logicModule from '../logic'
///....
class GuiModule extends ViewModule {
getSomeLabelText(state) {
return doSomeGuiStuff(logicModule.getValue(state));
}
}
То есть редьюсер запоминает последние состояние и его можно получить в обход пропсов?
Сам редьюсер ничего не запоминает, он получает то что надо через селекторы. тут несколько другая концепацая (общую идею можно почитать тут https://github.com/erikras/ducks-modular-redux ). То есть есть модуль, который включает в себя описание экшенов, редьюсер и селекторы.
Вместо конфига можно использовать декораторы методов, тогда не надо указывать ни имя, ни функцию.
Одним из лучших вариантов организации редьюсеров через классы мне представляется ngrx-actions. Мне немного не хватало в нем типизации, и т.к. автор забил на проект, то я его переписал. Но, в целом, мысли похожие.
Организация reducer'а через стандартный класс