Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
@NgModule({
declarations: [
MyApp,
],
imports: [
...
NgReduxModule,
StoreModule, // <============================== HERE!
...
],
entryComponents: [
MyApp,
],
providers: [
...
],
})
export class AppModule {
}
export interface FluxStandardAction<Payload, Meta = undefined> {
/**
* The `type` of an action identifies to the consumer the nature of the action that has occurred.
* Two actions with the same `type` MUST be strictly equivalent (using `===`)
*/
type: string;
/**
* The optional `payload` property MAY be any type of value.
* It represents the payload of the action.
* Any information about the action that is not the type or status of the action should be part of the `payload` field.
* By convention, if `error` is `true`, the `payload` SHOULD be an error object.
* This is akin to rejecting a promise with an error object.
*/
payload: Payload;
/**
* The optional `error` property MAY be set to true if the action represents an error.
* An action whose `error` is true is analogous to a rejected Promise.
* By convention, the `payload` SHOULD be an error object.
* If `error` has any other value besides `true`, including `undefined`, the action MUST NOT be interpreted as an error.
*/
error?: boolean;
/**
* The optional `meta` property MAY be any type of value.
* It is intended for any extra information that is not part of the payload.
*/
meta: Meta;
}
import { Injectable } from '@angular/core';
import { dispatch } from '@angular-redux/store';
import { FluxStandardAction } from 'flux-standard-action';
import {
MoodLogPushPayload,
MoodLogRemovePayload,
MoodLogUpdatePayload,
MoodLogPostPayload,
MoodLogDeletePayload,
MoodLogAssignPayload,
MoodLogPutPayload,
} from './mood.model';
// * actions
export type MoodLogGetAction = FluxStandardAction<null, null>;
export type MoodLogPostAction = FluxStandardAction<MoodLogPostPayload, null>;
export type MoodLogPutAction = FluxStandardAction<MoodLogPutPayload, null>;
export type MoodLogDeleteAction = FluxStandardAction<MoodLogDeletePayload, null>;
// * mutations
export type MoodLogPushAction = FluxStandardAction<MoodLogPushPayload, null>;
export type MoodLogUpdateAction = FluxStandardAction<MoodLogUpdatePayload, null>;
export type MoodLogAssignAction = FluxStandardAction<MoodLogAssignPayload, null>;
export type MoodLogRemoveAction = FluxStandardAction<MoodLogRemovePayload, null>;
@Injectable()
export class MoodActions {
// * actions
static readonly GET_LOGS = 'MOOD_GET_LOGS';
static readonly POST_LOG = 'MOOD_POST_LOG';
static readonly PUT_LOG = 'MOOD_PUT_LOG';
static readonly DELETE_LOG = 'MOOD_DELETE_LOG';
@dispatch()
getLogs = (): MoodLogGetAction => ({
type: MoodActions.GET_LOGS,
payload: null,
meta: null,
})
@dispatch()
postLog = (payload: MoodLogPostPayload): MoodLogPostAction => ({
type: MoodActions.POST_LOG,
payload,
meta: null,
})
@dispatch()
putLog = (payload: MoodLogPutPayload): MoodLogPutAction => ({
type: MoodActions.PUT_LOG,
payload,
meta: null,
})
@dispatch()
deleteLog = (payload: MoodLogDeletePayload): MoodLogDeleteAction => ({
type: MoodActions.DELETE_LOG,
payload,
meta: null,
})
// * mutations
static readonly PUSH_LOG = 'MOOD_PUSH_LOG';
static readonly UPDATE_LOGS = 'MOOD_UPDATE_LOGS';
static readonly ASSIGN_LOG = 'MOOD_ASSIGN_LOG';
static readonly REMOVE_LOG = 'MOOD_REMOVE_LOG';
@dispatch()
pushLog = (payload: MoodLogPushPayload): MoodLogPushAction => ({
type: MoodActions.PUSH_LOG,
payload,
meta: null,
})
@dispatch()
updateLogs = (payload: MoodLogUpdatePayload): MoodLogUpdateAction => ({
type: MoodActions.UPDATE_LOGS,
payload,
meta: null,
})
@dispatch()
assignLog = (payload: MoodLogAssignPayload): MoodLogAssignAction => ({
type: MoodActions.ASSIGN_LOG,
payload,
meta: null,
})
@dispatch()
removeLog = (payload: MoodLogRemovePayload): MoodLogRemoveAction => ({
type: MoodActions.REMOVE_LOG,
payload,
meta: null,
})
}
<ion-item-sliding *ngFor="let log of mLogList$ | async; let i = index;">
<button ion-item (click)="onClickLog(i)">
<span class="date">{{ log.actedAt | date : 'yyyy-MM-dd / h a' : '+0000' }}</span>
<span class="type">{{ log.name }}</span>
<button color="secondary" ion-button item-end>
수정
</button>
</button>
<ion-item-options>
<button ion-button color="danger" (click)="onDeleteMoodLog(i)">
삭제
</button>
</ion-item-options>
</ion-item-sliding>
export interface MoodLog {
moodLogId?: number;
type: string;
actedAt: Date;
createdAt: Date;
}
export interface MoodState {
moodLogList: MoodLog[];
}
export type MoodLogPostPayload = MoodLog;
export type MoodLogPutPayload = MoodLog;
export type MoodLogDeletePayload = MoodLog;
export type MoodLogPushPayload = MoodLog;
export type MoodLogUpdatePayload = MoodLog[];
export type MoodLogAssignPayload = MoodLog;
export type MoodLogRemovePayload = MoodLog;
import { Action } from 'redux';
import {
MoodActions,
MoodLogPushAction,
MoodLogUpdateAction,
MoodLogRemoveAction,
MoodLogAssignAction,
} from './mood.action';
import { MoodState } from './mood.model';
import deepCopy from 'deep-copy';
export const INITIAL_STATE: MoodState = {
moodLogList: [],
};
export function moodReducer(
state: MoodState = INITIAL_STATE,
action: Action,
): MoodState {
switch (action.type) {
case MoodActions.PUSH_LOG: {
const a = action as MoodLogPushAction;
const newState = deepCopy(state);
newState.moodLogList.push(a.payload);
return newState;
}
case MoodActions.UPDATE_LOGS: {
const a = action as MoodLogUpdateAction;
const newState = deepCopy(state);
newState.moodLogList = a.payload;
return newState;
}
case MoodActions.ASSIGN_LOG: {
const a = action as MoodLogAssignAction;
const newState = deepCopy(state);
const index = newState.moodLogList.findIndex(item =>
item.moodLogId === a.payload.moodLogId,
);
newState.moodLogList[index] = a.payload;
return newState;
}
case MoodActions.REMOVE_LOG: {
const a = action as MoodLogRemoveAction;
const newState = deepCopy(state);
const index = newState.moodLogList.findIndex(item =>
item.moodLogId === a.payload.moodLogId,
);
newState.moodLogList.splice(index, 1);
return newState;
}
}
return state;
}
import { call, takeLatest, takeEvery } from 'redux-saga/effects';
import { getMoodLogs, postMoodLog, putMoodLog, deleteMoodLog } from './mood.service';
import {
MoodActions,
MoodLogPostAction,
MoodLogPutAction,
MoodLogDeleteAction,
} from './mood.action';
import { ReflectiveInjector } from '@angular/core';
import camelcaseKeys from 'camelcase-keys';
const injector = ReflectiveInjector.resolveAndCreate([MoodActions]);
const ma = injector.get(MoodActions) as MoodActions;
function* getLogsSaga() {
try {
const res = yield call(getMoodLogs);
console.log('getLogsSaga res', res.data.value);
const logs = res.data.value.map(camelcaseKeys);
ma.updateLogs(logs);
} catch (error) {
console.error('error', error);
}
}
function* postLogSaga(action) {
try {
const a = action as MoodLogPostAction;
const res = yield call(postMoodLog, a.payload);
console.log('postLogSaga res', res);
a.payload.moodLogId = res.data.mood_log_id;
a.payload.createdAt = res.data.created_at;
ma.pushLog(a.payload);
} catch (error) {
console.error('error', error);
}
}
function* putLogSaga(action) {
try {
const a = action as MoodLogPutAction;
console.log('putLogSaga a', a);
yield call(putMoodLog, a.payload);
ma.assignLog(a.payload);
} catch (error) {
console.error('error', error);
}
}
function* deleteLogSaga(action) {
try {
const a = action as MoodLogDeleteAction;
yield call(deleteMoodLog, a.payload);
ma.removeLog(a.payload);
} catch (error) {
console.error('error', error);
}
}
export default function* moodSaga() {
yield takeLatest(MoodActions.GET_LOGS, getLogsSaga);
yield takeEvery(MoodActions.POST_LOG, postLogSaga);
yield takeEvery(MoodActions.PUT_LOG, putLogSaga);
yield takeEvery(MoodActions.DELETE_LOG, deleteLogSaga);
}
import { select } from '@angular-redux/store';
import { Observable } from 'rxjs/Observable';
import { MoodLog } from './../mood/mood.model';
@Component({
selector: ...
templateUrl: ...
})
export class MoodPage {
@select(['mood', 'moodLogList'])
readonly mLogList$: Observable<MoodLog[]>;
}
import { select } from '@angular-redux/store';
import { Observable } from 'rxjs/Observable';
import { MoodLog } from './../mood/mood.model';
export function listSelector(state) {
return state.mood.moodLogList
.sort((a, b) => (new Date(b.actedAt).getTime() - new Date(a.actedAt).getTime()));
}
@Component({
selector: ...
templateUrl: ...
})
export class MoodPage {
@select(listSelector)
readonly mLogList$: Observable<MoodLog[]>;
}
@Component({
selector: ...
templateUrl: ...
})
export class MoodPage {
@select(listSelector)
readonly mLogList$: Observable<MoodLog[]>;
constructor(
public moodActions: MoodActions,
) {
super();
moodActions.getLogs();
}
}
ngAfterViewInit() {
this.mLogList$.subscribe((moodLogList) => {
// Do Something
});
}
async onClickSomething() {
const logList = await this.mLogList$.take(1).toPromise();
// Do Something
}
import { NgRedux } from '@angular-redux/store';
import { createLogger } from 'redux-logger';
import { NgModule } from '@angular/core';
import { rootReducer } from './store';
import createSagaMiddleware from 'redux-saga';
import { all } from 'redux-saga/effects';
import { MoodActions } from './../pages/mood/mood.action';
import moodSaga from '../pages/mood/mood.saga';
const sagaMiddleware = createSagaMiddleware();
@NgModule({
providers: [
MoodActions,
// more actions here!
],
})
export class StoreModule {
constructor(
public ngRedux: NgRedux<any>,
) {
this.ngRedux.configureStore(
rootReducer,
{},
[createLogger(), sagaMiddleware],
);
function* rootSaga() {
yield all([
moodSaga(),
// more sagas here!
]);
}
sagaMiddleware.run(rootSaga);
}
}
import { combineReducers } from 'redux';
import { composeReducers, defaultFormReducer } from '@angular-redux/form';
import { moodReducer } from '../pages/mood/mood.reducer';
export const rootReducer = composeReducers(
defaultFormReducer(),
combineReducers({
mood: moodReducer,
// more reducers here!
// e.g) login: loginReducer
}),
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment