Pull to refresh

Comments 14

UFO just landed and posted this here
Про редакс тоже была хорошая статья. Столько кода и так мало смысла. Когда Вас с рынка выгонят всех, дармоеды?

Зря не читали! Дальше встречаются такие перлы, как, например этот кусок кода:


export const  someReduceLabelActionCreator =  FetchSaga.bind(this, SOME_REDUCE_LABEL);
UFO just landed and posted this here
Я использую вот такую конструкцию чтоб избавится от бардака:
Акшен
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, использование наследования)

Очень интересный подход. Я как-то зациклился на том, что один reducer обслуживает одну страницу. И есть еще несколько вспомогательных reducer'ов, для виджетов. В вашем случае каждый модуль несет единственную ответственность. Что позволяет их использовать повторно более эффективно. Эту идею стоит обдумать.

Про страницы — я использовал другой подход, были такие модули отдельно для GUI и для бизнес логики. И например если в каком-то модуле GUI нужно было вывести значение из бизнес-модуля, то грубо говоря так


import logicModule from '../logic'
///....
class GuiModule extends ViewModule {

    getSomeLabelText(state) {
        return doSomeGuiStuff(logicModule.getValue(state));
    }
}

То есть редьюсер запоминает последние состояние и его можно получить в обход пропсов?

Сам редьюсер ничего не запоминает, он получает то что надо через селекторы. тут несколько другая концепацая (общую идею можно почитать тут https://github.com/erikras/ducks-modular-redux ). То есть есть модуль, который включает в себя описание экшенов, редьюсер и селекторы.

Вместо конфига можно использовать декораторы методов, тогда не надо указывать ни имя, ни функцию.

Велосипеды это круто, они помогают учиться, автор взгляни на MobX, большинство велосипедов пытаются решить одну и туже проблему (булертплейт), там она уже решена

Одним из лучших вариантов организации редьюсеров через классы мне представляется ngrx-actions. Мне немного не хватало в нем типизации, и т.к. автор забил на проект, то я его переписал. Но, в целом, мысли похожие.

Sign up to leave a comment.

Articles