redux-model-s
v0.0.7
Published
Working with redux through models. Involve OOP in redux. Do it more power and add DRY.
Downloads
2
Maintainers
Readme
Redux-models. OOP style.
Background
In this approach you have only model with all the logic (getting data from server, converting it into client view, action creators, reducers etc …) and standard redux reducer for linking your model with reducer:
Goals
- Move all logic (action creator, api call, reducer, data transformations server-client-server, validation) in one file - MODEL
- Write once used everywhere. It's OOP style - when you base models and sub models. Can all advantages from OOP.
- Reduce code, reduce dynamic objects calling
- No dependencies
- Cross-platform - can be used in React-Native
Installation
Using npm:
$ npm install --save redux-model-s
Using yarn:
$ yarn add redux-model-s
Usage
/**
* pokemon.model.js
*/
import model from 'redux-model-s/lib/models/base.model';
import urls from '../constants/urls.constant';
import { isEmpty } from '../utils/helper';
class pokemonsModel extends model {
static MODEL_NAME = 'pokemonsModel';
static TYPE_REQUEST = 'REQUEST_POKEMONS';
static TYPE_FROM_SERVER = 'GET_POKEMONS';
static TYPE_CLEAR = 'CLEAR_POKEMONS';
constructor(props) {
super(props);
};
static apiGet(requestMethod, params = {}) {
const { limit, offset } = this.toServer(params);
const url = urls.pokeball.getPokemons();
const queryParams = (offset !== undefined)
? { limit, offset: (offset + limit) }
: { limit };
return requestMethod(url, {}, queryParams);
};
static create() {
const props = super.create();
return {
...props,
items: [],
isFirstLoading: false,
paginator: {},
hasMore: false
};
};
static toClient(serverModel) {
if (!serverModel) {
return this.create();
}
const { meta, objects } = serverModel;
const paginator = this.toClientPaginator(meta);
const items = objects
.map((pokemon) => ({
id: pokemon.pkdx_id,
name: pokemon.name,
// avatar: `http://pokeapi.co/media/img/${pokemon.pkdx_id}.png`,
avatar: `https://raw.githubusercontent.com/PokeAPI/pokeapi/master/data/v2/sprites/pokemon/model/${pokemon.pkdx_id}.png`,
types: pokemon.types
}));
return {
items,
paginator
};
};
static toClientPaginator(serverModel) {
const paginator = {
limit: serverModel.limit,
next: serverModel.next,
offset: serverModel.offset,
previous: serverModel.previous,
total_count: serverModel.total_count
};
return paginator;
};
static toServer(params) {
if (isEmpty(params)) {
return {};
}
return {
limit: params.limit,
offset: params.offset,
};
}
static reduceGet(stateModel, action) {
const { modelClient, model } = action.payload;
const { items: _items } = stateModel;
const { items, paginator } = modelClient;
return {
[model.MODEL_NAME]: {
items: [..._items, ...items],
paginator,
hasMore: paginator.offset < paginator.total_count,
isLoading: false,
isFirstLoading: false
}
};
};
static reduceRequest(stateModel, action, state) {
const { model } = action.payload;
const newState = super.reduceRequest(stateModel, action, state)[model.MODEL_NAME];
const { items, isLoading } = newState;
return {
[model.MODEL_NAME]: {
...stateModel,
isFirstLoading: isLoading && (!items || !items.length)
}
};
};
}
export {
pokemonsModel,
};
Advanced Usage
You can fill reducers with any model
/**
* pokemon.reducer.js
*/
import { apiReducer } from 'redux-model-s/lib/reducers/api.reducer';
import { pokemonModel } from '../models/pokemon.model';
import { pokemonsModel } from '../models/pokemons.model';
const DEFAULT_STATE = {
[pokemonModel.MODEL_NAME]: pokemonModel.create(),
[pokemonsModel.MODEL_NAME]: pokemonsModel.create(),
};
export default (state = DEFAULT_STATE, action) => {
return apiReducer(state, action);
};
Examples
The source includes example that should help you get started.
Questions?
If you have any questions, please submit an Issue with the "question"