1.2.1 • Published 4 years ago

redux-class-implementation v1.2.1

Weekly downloads
-
License
ISC
Repository
-
Last release
4 years ago

redux-class-implementation

An implementation of redux in typescript with classes instead of plain objects.

Class implementation to :

  • avoid selectors
  • avoid repeating function in components to format datas.
  • avoid redundant checking, selectors, etc... Everything is centralized and never repeated twice.
  • enable the ability to remove a significant amount of code from component/container side.
  • remove action types
  • remove reducer

Full example with react-native here

Models

Before

const Todo {
    id: string;
    content: string
    created_at: Date;
}

Now

import { State, Collection } from "redux-class-implementation"

interface TodoParameters {
    id: string;
    content: string
    created_at: Date;
}

class Todo extends State {

    constructor(todo: TodoParameters){
        super(todo)
    };

    //Getters : public
    public ID = (): string => this.Get().id
    public Content = (): string => this.Get().content
    public CreatedAt = (): Date => this.Get().created_at
}

class TodoList extends Collection {

    constructor(list: Todo[] = []){
        super(list, Todo)
    }
    
    SortByContent = (type: sortType = 'asc') => new TodoList((_.orderBy(this.ToPlain(), ['content'], [type])))
    SortByCreateDate = (type: sortType = 'asc') => new TodoList(_.orderBy(this.ToPlain(), ['created_at'], [type]))
}

Actions

Before

import Todo from '../../models'

export const CREATE_TODO = 'CREATE_TODO'

export const CreateTodo = (todo: Todo) => {
    return {
    	type: CREATE_TODO, 
        payload: todo
    }
}

Now

import { Action } from 'redux-class-implementation'
import TodoState, { CONFIG } from '../states/todo'
import Todo from '../../models'

class TodoAction extends Action {

    constructor(stateClass: any){    
        super(stateClass, CONFIG.STORE_KEY)
    }
	
    //The Exec function is a method from the Action class.
    //It requires a function in parameter inside which you can run what you need
    //from the state linked with this action class. (handle to avoid action types)
    CreateTodo = (todo: Todo) => this.Exec((state: any) => state.AddTodo(t))
}

export default new TodoAction(TodoState)

Reducer

Before

import { CREATE_TODO } from '../actions/todo'
import { Todo } from '../../models'

interface IStateObject {
    todolist: Todo[]
}

export default (state: any = DEFAULT_STATE, action: any): IStateObject => {
    const {type, payload} = action

    switch (type){

        case CREATE_TODO:
            const todolist = state.todo.slice()
            todolist.push(payload)
            return { ...state, todolist }
            
        default:
            return state
    }
}

const DEFAULT_STATE: IStateObject = {
    todolist: []
}

Now

none

State

Before

none

Now

import { State } from 'redux-class-implementation'
import { Todo, TodoList, TodoParameters } from '../../models'

interface IStateObject {
    todolist: TodoParameters[]
}

export default class TodoState extends State {

    constructor(initial: IStateObject = CONFIG.DEFAULT_STATE){
        super({ 
		todolist: new TodoList(initial.todolist) 
	})
    }
	//The exec function has the same working system than the one Action
	//but this time, it updates the state, and return it, when done.
    public AddTodo = (todo: Todo) => this.Exec((state) => state.todolist.Post(todo))
    public GetTodoList = (): TodoList => this.Get().todolist
}

//This config variable has to be in each state class file
//It allows to remove the reducer parts.
export const CONFIG = {
    STORE_KEY: 'todo',
    DEFAULT_STATE: {
    	todolist: []
    }
}

Store

Before

import { createStore, applyMiddleware, combineReducers } from 'redux'
import todoReducer from '../reducers/todo'

const createReducer = (): object => {
  return {
    todo: todoReducer
  }
}

export default (): any => createStore(
		combineReducers(createReducer()),
		applyMiddleware(promise)
)

Now

import { createStore, applyMiddleware } from 'redux'
import { initialize, prevStateHandlerMiddleware } from 'redux-class-implementation'
import promise from 'redux-promise'

import { CONFIG as TODO_CONFIG } from './states/todo'

export default (): any => createStore(
	initialize([ TODO_CONFIG ]),
	applyMiddleware(promise, prevStateHandlerMiddleware) //this last middleware is used to save the previous state each time a new one is injected.
)

Connect

Before

import { CreateTodo } from '../../redux/actions/todo'
import { connect } from 'react-redux'

const mapStateToProps = (state) => {
    const { todolist } = state.todo 
    return {
        todolist
    }
}

export default connect(mapStateToProps, {
    createTodo: CreateTodo,
})(Connect)

Now

import TodoAction from '../../redux/actions/todo'
import { connect } from 'redux-class-implementation'

const stateToProps = {
    //always pick up the state you want using the extend method from Action that will
    //transform a state plain object into a State Class
    todolist: (state) => TodoAction.Extend(state).GetTodoList()
}

export default connect(stateToProps, {
    createTodo: TodoAction.CreateTodo,
})(TodoList)

Component : Todo

Before

const render = () => {
  const {id, created_at, content} = this.props.todo
  return (
    <div>
      <span>{id}</span>
      <span>{created_at}</span>
      <span>{content}</span>
    </div>
  )
}

Now

const render = () => {
  const {todo} = this.props
  return (
    <div>
      <span>{todo.ID()}</span>
      <span>{todo.CreatedAt()}</span>
      <span>{todo.Content()}</span>
    </div>
  )
}

Component : Todolist

Before

import _ from 'lodash'

getListSortedByContent = () => {
  const { todolist } = this.props
  return _.orderBy(todolist.slice(), ['content'], ['asc'])
}

getListSortedByCreateDate = () => {
  const { todolist } = this.props
  return _.orderBy(todolist.slice(), ['created_at'], ['desc'])
}

const getList = () => {
    return shouldSort() ?
    this.getListSortedByContent()
    : 
    this.getListSortedByCreateDate()
}

return (
    <div>
        {getList().map((todo, index) => {
            return <Todo todo={todo} key={index} />
        })}
    </div>
)

Now

const getList = () => {
    const { todolist } = this.props
    return shouldSort() ?
    todolist.SortByContent('asc').Get()
    : 
    todolist.SortByCreateDate('desc').Get()
}

return (
    <div>
        {getList().map((todo, index) => {
            return <Todo todo={todo} key={index} />
        })}
    </div>
)
1.2.1

4 years ago

1.1.4

4 years ago

1.1.3

4 years ago

1.1.2

4 years ago

1.1.1

4 years ago

1.1.0

4 years ago

1.0.9

4 years ago

1.0.8

4 years ago

1.0.7

4 years ago

1.0.6

4 years ago

1.0.5

4 years ago

1.0.4

4 years ago

1.0.3

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago