1

I am currently dispatching an event to retrieve all data from the backend, and with this dispatch I popularize the state copy.

So far so good, the problem is if there is nothing on the backend that I would need to dispatch an event to create the data on it and in a new copy of the state.

For this I used a selector to check if there is already something in the state, because if there is one there will be in the backend, his problem is that the result arrives multiple and the delay is the same as in the image below:

enter image description here Here is my code:

APP COMPONENT

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
    title = 'webwhatsapp';
    protected peoples: Array<IPeople> = [
        { id: '0', isMain: true, name: 'THIAGO DE BONIS CARVALHO SAAD SAUD', avatar: 'assets/users/thiagobonis.jpg', messages: null },
        { id: '1', isMain: false, name: 'BILL GATES', avatar: 'assets/users/billgates.jpg', messages: null },
        { id: '2', isMain: false, name: 'STEVE JOBS', avatar: 'assets/users/stevejobs.jpg', messages: null },
        { id: '3', isMain: false, name: 'LINUS TORVALDS', avatar: 'assets/users/linustorvalds.jpg', messages: null },
        { id: '4', isMain: false, name: 'EDSGER DIJKSTRA', avatar: 'assets/users/dijkstra.jpg', messages: null },
    ];

    constructor(private readonly peopleDispatchService: PeopleDispatchService, private readonly peopleSelectorsService: PeopleSelectorsService) {}

    ngOnInit(): void {
        this.peopleDispatchService.getAll();
        this.peopleSelectorsService.total.subscribe((total) => {
            console.log(total);
            if (total === 0) {
                // this.peoples.forEach((people) => this.peopleDispatchService.create(people));
            } else {
            }
        });
    }
}

REDUCERS

export interface State extends EntityState<IPeople> {
    error: IRequestError | null;
    loading: boolean;
}

export const adapter: EntityAdapter<IPeople> = createEntityAdapter<IPeople>({
    selectId: (people) => people.id,
});

const INIT_STATE: State = adapter.getInitialState({
    error: null,
    loading: true,
});

const peopleReducer = createReducer(
    INIT_STATE,
    on(fromPeopleAction.GET_ALL_SUCCESS, (state, { peoples }) => adapter.addMany(peoples, { ...state, loading: false })),
    on(fromPeopleAction.GET_ALL_FAIL, (state, { error }) => ({ ...state, error, loading: false })),
    on(fromPeopleAction.CREATE_SUCCESS, (state, { people }) => adapter.addOne(people, { ...state, loading: false })),
    on(fromPeopleAction.CREATE_FAIL, (state, { error }) => ({ ...state, error, loading: false })),
    on(fromPeopleAction.DELETE_SUCCESS, (state, { id }) => adapter.removeOne(id, { ...state, loading: false })),
    on(fromPeopleAction.DELETE_FAIL, (state, { error }) => ({ ...state, error, loading: false }))
);

export function reducer(state: State | undefined, action: Action) {
    return peopleReducer(state, action);
}

EFFECTS

@Injectable()
export class Effects {
    constructor(private action$: Actions, private backend: BackendService, private requestHandler: RequestHandlerService) {}

    getAll$ = createEffect(() =>
        this.action$.pipe(
            ofType(fromPeopleActions.GET_ALL),
            mergeMap(() => {
                return this.backend.getAll().pipe(
                    map((peoples) => fromPeopleActions.GET_ALL_SUCCESS({ peoples })),
                    catchError((error) => of(fromPeopleActions.GET_ALL_FAIL({ error: this.requestHandler.getError(error) })))
                );
            })
        )
    );

    create$ = createEffect(() =>
        this.action$.pipe(
            ofType(fromPeopleActions.CREATE),
            mergeMap((action) => {
                return this.backend.create(action.people).pipe(
                    map((people) => fromPeopleActions.CREATE_SUCCESS({ people })),
                    catchError((error) => of(fromPeopleActions.CREATE_FAIL({ error: this.requestHandler.getError(error) })))
                );
            })
        )
    );

    deleteAll$ = createEffect(() =>
        this.action$.pipe(
            ofType(fromPeopleActions.DELETE),
            mergeMap((action) => {
                return this.backend.delete(action.id).pipe(
                    map(() => fromPeopleActions.DELETE_SUCCESS({ id: action.id })),
                    catchError((error) => of(fromPeopleActions.DELETE_FAIL({ error: this.requestHandler.getError(error) })))
                );
            })
        )
    );
}

SELECTORS

const featureSelector = createFeatureSelector<State>('people');

export const { selectIds, selectEntities, selectAll, selectTotal } = adapter.getSelectors(featureSelector);

export const getError = createSelector(featureSelector, (state: State) => state.error);
export const getIsMain = createSelector(featureSelector, (state: State) => {
    state.ids.forEach((id: any) => {
        if (state.entities[id].isMain) {
            return state.entities[id];
        }
    });
});
Shlok Nangia
  • 2,355
  • 3
  • 16
  • 24

1 Answers1

0

I would recommend you to use the same effect to detect the empty backend state.

In the getAll$ you can check after response if backend is empty, if it is - dispatch an action to populate it. For example PopulatePeople.

    getAll$ = createEffect(() =>
        this.action$.pipe(
            ofType(fromPeopleActions.GET_ALL),
            mergeMap(() => {
                return this.backend.getAll().pipe(
                    tap(people => people.length === 0 ? this.store.dispatch(fromPeopleActions.POPULATE()) : undefined)
                    // ....
                );
            })
        )
    );

Then you need an another effect to listen to PopulatePeople.

populate$ = createEffect(() =>
  this.action$.pipe(
    ofType(fromPeopleActions.POPULATE),
      tap(() => this.peoples.forEach((people) => this.peopleDispatchService.create(people))),
  )
);

in this case POPULATE is triggered only when backend is really empty.

satanTime
  • 12,631
  • 1
  • 25
  • 73