# Directory Structure

With Retux it is recommended always start with the basic structure and perform small refactoring as it scales.

# Basic Structure

├── src
│   ├── retux-store
│   │   ├── modules
│   │   │   ├── todos.ts
│   │   │   ├── visibilityFilter.ts
│   │   │   └── index.ts
│   │   └── index.ts
│   │
│   ├── containers
|   |   └── List.tsx
│   │
│   ├── components
│   │   └── App.tsx
│   │
│   └── index.tsx
│
└── package.json

# Retux Modules

Let's start with the Retux modules directory. Each basic module has at least four exports: ActionCatalog, initState, State, actionHandlers.

import { CreateActionCatalog, ActionHandlers } from 'retux'

export type ActionCatalog = CreateActionCatalog<{
  COUNTER$INCREMENT: {
    payload: {
      /** default 1 */
      step?: number
    }
  }
  COUNTER$DECREMENT: {
    payload: {
      /** default 1 */
      step?: number
    }
  }
}>

export const initState = {
  count: 0
}

export type State = Readonly<typeof initState>

export const actionHandlers: ActionHandlers<State, ActionCatalog> = {
  COUNTER$INCREMENT: (state, { payload: { step = 1 } }) => ({
    count: state.count + step
  }),
  COUNTER$DECREMENT: (state, { payload: { step = 1 } }) => ({
    count: state.count - step
  })
}

When a module gets too large, you can always split it into seperated files.

├── src
│   ├── retux-store
│   │   ├── modules
│   │   │   ├── todos
│   │   │   │   ├── state.ts
│   │   │   │   ├── action-catalog.ts
│   │   │   │   ├── action-handlers.ts
│   │   │   │   ├── index.ts
// state.ts
export const initState = {
  count: 0
}

export type State = Readonly<typeof initState>
// action-catalog.ts
import { CreateActionCatalog } from 'retux'

export type ActionCatalog = CreateActionCatalog<{
  COUNTER$INCREMENT: {
    payload: {
      /** default 1 */
      step?: number
    }
  }
  COUNTER$DECREMENT: {
    payload: {
      /** default 1 */
      step?: number
    }
  }
}>
// action-handlers.ts
import { ActionHandlers } from 'retux'
import { State } from './state'
import { ActionCatalog } from './action-catalog'

export const actionHandlers: ActionHandlers<State, ActionCatalog> = {
  COUNTER$INCREMENT: (state, { payload: { step = 1 } }) => ({
    count: state.count + step
  }),
  COUNTER$DECREMENT: (state, { payload: { step = 1 } }) => ({
    count: state.count - step
  })
}
// index.ts
export { initState, State } from './state'
export { ActionCatalog } from './action-catalog'
export { actionHandlers } from './action-handlers'

# Module Root

In retux-store/modules/index.ts we combine modules.

// src/retux-store/modules/index.ts
import { combineReducers, createStore as createReduxStore } from 'redux'
import { createReducer, proxyCombineUniqueObjects, Action } from 'retux'
import * as Todos from './todos'
import * as VisibilityFilter from './visibilityFilter'

export type StoreActionCatalog = Todos.ActionCatalog &
  VisibilityFilter.ActionCatalog
  
export type StoreActionType = ActionType<StoreActionCatalog>

export type StoreAction<T extends StoreActionType = StoreActionType> = Action<
  StoreActionCatalog,
  T
>

export const storeActionHandlers = proxyCombineUniqueObjects(
  Todos.actionHandlers,
  VisibilityFilter.actionHandlers
)

export type StoreState = Readonly<{
  todos: Todos.State
  visibilityFilter: VisibilityFilter.State
}>

export const rootReducer = combineReducers({
  todos: createReducer(Todos.initState, Todos.actionHandlers),
  visibilityFilter: createReducer(
    VisibilityFilter.initState,
    VisibilityFilter.actionHandlers
  )
})

Here shows usage with Redux's combineReducers. Each module has a separated state. Modules can also share a single state.

# Create Redux Store

Setup Redux store and middlewares.

// src/retux-store/index.ts
import { applyMiddleware, createStore as createReduxStore } from 'redux'
import { createEpicMiddleware } from 'redux-observable'
import { rootReducer } from './modules'

export const createStore = () => {
  return createReduxStore(rootReducer)
}

# With Action Creators

If you prefer Action Creators, add:

├── src
│   ├── retux-store
│   │   ├── actions.ts

In retux-store/actions.ts we generate and customize Action Creators.

import { proxyActionCreators } from 'retux'
import { storeActionHandlers, StoreAction } from './index'

export const action = proxyActionCreators(
  storeActionHandlers,
  {
    OVERWRITE_ACTION: (id: string, text: string): StoreAction<'TODOS$EDIT'> => ({
      type: 'TODOS$EDIT',
      payload: { id, text }
    })
  }
)

See example (opens new window) for more Action Creator patterns.

As it scales, you can split action creators into different files.

├── src
│   ├── retux-store
│   │   ├── actions
│   │   │   ├── todos.ts
│   │   │   ├── visibilityFilter.ts
│   │   │   └── index.ts

# State Sharing

You can have a single state for the entire store.

├── src
│   ├── retux-store
│   │   ├── state
│   │   │   └── index.ts
│   │   ├── modules
│   │   │   ├── todos.ts
│   │   │   ├── visibilityFilter.ts
│   │   │   └── index.ts

Or just share state among a few modules.

├── src
│   ├── retux-store
│   │   ├── modules
│   │   │   ├── todos
│   │   │   │   ├── state.ts
│   │   │   │   ├── basic.ts
│   │   │   │   ├── bulk.ts
│   │   │   │   └── index.ts
│   │   │   ├── visibilityFilter.ts
│   │   │   └── index.ts

See example (opens new window).todos/basic.ts and todos/bulk.ts export ActionCatalog and actionHandlers which are combined at todos/index.ts.