Trouble understanding how to denormalize my state using Angular6, @NGRX and Normalizr

409 Views Asked by At

I am creating a small app in Angular6 which is using @NGRX for state management and Nomalizr to for de/normalization of the data. The normalization happens in an effect and my denormalization needs to happen in a selector.

I am having an issue understanding what to do when attempting to denormalize my state in the selector and am having issues getting it to work.

Here is my code:

My actions:

import {Action} from "@ngrx/store";

export const GET_ARTICLE = 'Get_Article';
export const GET_ARTICLE_LOAD_SUCCESS = 'Get_Article_Load_Success';

export class GetArticleAction implements Action {
  readonly type = GET_ARTICLE;

  constructor(public payload: string) {}
}

export class GetArticleLoadSuccess implements Action {
  readonly type = GET_ARTICLE_LOAD_SUCCESS;

  constructor(public payload) {}
}

export type All = GetArticleAction | GetArticleLoadSuccess;

My component code that fires the action and also the subscription to the observable which will watch for state changes:

 ngOnInit() {
    this.store.pipe(
        select(getArticles)
    ).subscribe((response) => {
        console.log(response);
    })
  }

  getArticle(id: string) {
    this.store.dispatch(new GetArticleAction(id));
  }
}

My effect:

 @Effect()
  public getArticle$: Observable<Action> = this.actions$.pipe(
      ofType(GET_ARTICLE),
      switchMap((action: GetArticleAction) => {
        // we don't user the action payload here as we are mocking the API call
        return of(mockData)
      }),
      switchMap((response: IArticle) => {
        const normalizedData = normalize(response, article);
        return of(normalizedData);
      }),
      flatMap((normalizedData) => [
        new GetArticleLoadSuccess(normalizedData)
      ])
  )

And my reducer:

const initialState: ArticleState = {
  articles: [],
  comments: [],
  users: []
};

export function reducer(state = initialState, action: fromActions.All): ArticleState {
  switch (action.type) {
    case fromActions.GET_ARTICLE: {
      return Object.assign({}, state);
    }
    case fromActions.GET_ARTICLE_LOAD_SUCCESS: {
      return Object.assign({}, action.payload);
    }
    default: {
      return state;
    }
  }
}

export const getArticleState = createFeatureSelector<ArticleState>('articleState');
export const getArticles = createSelector(getArticleState, (state: ArticleState) => {
  return denormalize([], article, state.entities);
});

My data is as follows:

import {IArticle} from "./article";

export const mockData: IArticle = {
  "id": "123",
  "author": {
    "id": "1",
    "name": "Paul"
  },
  "title": "My awesome blog post",
  "comments": [
    {
      "id": "324",
      "commenter": {
        "id": "2",
        "name": "Nicole"
      }
    }
  ]
};

I can get the normaliaztion working as when I check my store the state object looks as follows:

    {
  articleState: {
    entities: {
      users: {
        '1': {
          id: '1',
          name: 'Paul'
        },
        '2': {
          id: '2',
          name: 'Nicole'
        }
      },
      comments: {
        '324': {
          id: '324',
          commenter: '2'
        }
      },
      articles: {
        '123': {
          id: '123',
          author: '1',
          title: 'My awesome blog post',
          comments: [
            '324'
          ]
        }
      }
    },
    result: '123'
  }
}

As you can see, I created a selector that will return the denormalized state but I am at a loss as to what I need to provide to this function. I have checked the Normalizr docs and I can't seem to understand what needs to be done. Can anyone see maybe where I am going wrong here or how I implement the denormalztion function in the selector to return the denormalized data back to the component? Thanks

0

There are 0 best solutions below