NGRX Workshop Notes - Folder Structure
Tags: angular, javascript, webdev, ngrx
Published: 2020-04-03 01:36:20


Following the LIFT principle: 

- **L**ocating our code is easy
- **I**dentify code at a glance
- **F**lat file structure for as long as possible
- **T**ry to stay DRY - don’t repeat yourself

---

# Key Takeaways

- Put state in a shared place separate from features
- Effects, components, and actions belong to features
- Some effects can be shared
- Reducers reach into modules’ action barrels

---
---


# Folder structure followed in the workshop

```
├─ books\
│     actions\
│         books-api.actions.ts
│         books-page.actions.ts
│         index.ts                  // Includes creating names for the exports
│      books-api.effects.ts
│     
├─ shared\
│       state\
│          {feature}.reducer.ts     // Includes state interface, initial interface, reducers and local selectors
│          index.ts
│ 
```

- The index file in the _actions_ folder was using action barrels like the following:

```typescript
import * as BooksPageActions from "./books-page.actions";
import * as BooksApiActions from "./books-api.actions";

export { BooksPageActions, BooksApiActions };
```

- This made easier and more readable at the time of importing it:
```
import { BooksPageActions } from "app/modules/book-collection/actions";
```

---
---

## Folder structure followed in example app from @ngrx

```
├─ books\
│     actions\
│         books-api.actions.ts
│         books-page.actions.ts
│         index.ts                  // Includes creating names for the exports
│     effects\
|         books.effects.spec.ts 
|         books.effects.ts 
|     models\
|         books.ts 
│     reducers\
|         books.reducer.spec.ts 
|         books.reducer.ts 
|         collection.reducer.ts 
|         index.ts 
│     
├─ reducers\
│        index.ts  /// Defines the root state and reducers
│ 
```

- The index file under the _reducers_ folder is in charge of setting up the reducer and state

```typescript
import * as fromSearch from '@example-app/books/reducers/search.reducer';
import * as fromBooks from '@example-app/books/reducers/books.reducer';
import * as fromCollection from '@example-app/books/reducers/collection.reducer';
import * as fromRoot from '@example-app/reducers';

export const booksFeatureKey = 'books';

export interface BooksState {
  [fromSearch.searchFeatureKey]: fromSearch.State;
  [fromBooks.booksFeatureKey]: fromBooks.State;
  [fromCollection.collectionFeatureKey]: fromCollection.State;
}

export interface State extends fromRoot.State {
  [booksFeatureKey]: BooksState;
}

/** Provide reducer in AoT-compilation happy way */
export function reducers(state: BooksState | undefined, action: Action) {
  return combineReducers({
    [fromSearch.searchFeatureKey]: fromSearch.reducer,
    [fromBooks.booksFeatureKey]: fromBooks.reducer,
    [fromCollection.collectionFeatureKey]: fromCollection.reducer,
  })(state, action);
}
```

- The index file under `app/reducers/index.ts` defines the meta-reducers, root state, and reducers

```typescript
/**
 * Our state is composed of a map of action reducer functions.
 * These reducer functions are called with each dispatched action
 * and the current or initial state and return a new immutable state.
 */
export const ROOT_REDUCERS = new InjectionToken<
  ActionReducerMap<State, Action>
>('Root reducers token', {
  factory: () => ({
    [fromLayout.layoutFeatureKey]: fromLayout.reducer,
    router: fromRouter.routerReducer,
  }),
});
```

Personally, I like how the `example-app` is organized. One of the things that I will add is to have all the folders related to ngrx in a single folder:

```
├─ books\
│     store\
│        actions\
│            books-api.actions.ts
│            books-page.actions.ts
│            index.ts                  // Includes creating names for the exports
│        effects\
|            books.effects.spec.ts 
|            books.effects.ts 
|        models\
|            books.ts 
│        reducers\
|            books.reducer.spec.ts 
|            books.reducer.ts 
|            collection.reducer.ts 
|            index.ts 
│     
├─ reducers\
│        index.ts  /// Defines the root state and reducers
│ 
```