Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add NgRx, HMR state management, Redux dev tools
- Loading branch information
1 parent
e16ff29
commit 0e06dbc
Showing
21 changed files
with
327 additions
and
48 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
|
||
|
||
/* | ||
This is our "Barrels" index | ||
Here we can just export all individual things (in this folder) | ||
We're also using TypeScript2's new "paths" to create non-directory import locations | ||
So instead of having to do something crazy like: "from '../../app/'" | ||
We can just do: | ||
import { AppState } from 'app'; | ||
Makes life easier! | ||
*/ | ||
|
||
export * from './app.component'; | ||
export * from './app.routes'; | ||
|
||
export * from './state/app.reducer'; | ||
export * from './state/app-state'; | ||
export * from './state/hmr'; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Model definition for the (immutable) application state. | ||
*/ | ||
import { TypedRecord, makeTypedFactory } from 'typed-immutable-record'; | ||
import { List } from 'immutable'; | ||
|
||
// The TypeScript interface that defines the application state's properties. | ||
// This is to be imported wherever a reference to the app state is used | ||
// (reducers, components, services...) | ||
export interface AppState { | ||
loggedIn: boolean; | ||
loggedInUser: {}; | ||
} | ||
|
||
// An Immutable.js Record implementation of the AppState interface. | ||
// This only needs to be imported by reducers, since they produce new versions | ||
// of the state. Components should only ever read the state, never change it, | ||
// so they should only need the interface, not the record. | ||
export interface AppStateRecord extends TypedRecord<AppStateRecord>, AppState { } | ||
|
||
// An Immutable.js record factory for the record. | ||
export const appStateFactory = makeTypedFactory<AppState, AppStateRecord>({ | ||
loggedIn : false, | ||
loggedInUser: {} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* The main (and only) @ngrx/store reducer for the application. | ||
* | ||
* This implements the application's core logic by handling actions | ||
* and producing new versions of the immutable AppState record | ||
* based on those actions. | ||
*/ | ||
import { ActionReducer, Action } from '@ngrx/store'; | ||
import { List, Range } from 'immutable'; | ||
import { AppStateRecord, appStateFactory } from 'app'; | ||
|
||
// Action definitions | ||
export const LOGIN_USER = 'LOlGIN_USER'; | ||
export const LOGOUT_USER = 'LOGOUT_USER'; | ||
|
||
// The reducer function. Receives actions and produces new application states. | ||
export const appReducer: ActionReducer<AppStateRecord> = (state = makeInitialState(), action: Action) => { | ||
|
||
switch (action.type) { | ||
|
||
case LOGIN_USER: | ||
console.log(action.payload); | ||
// state.set('loggedInUser', action.payload); | ||
// state.set('loggedIn', true); | ||
return state.merge({ loggedInUser: action.payload, loggedIn: true }); | ||
|
||
case LOGOUT_USER: | ||
return state.merge(makeInitialState()); | ||
|
||
default: | ||
return state; | ||
} | ||
} | ||
|
||
// Initial AppState, used to bootstrap the reducer. | ||
function makeInitialState() { | ||
return appStateFactory({ | ||
loggedIn: false, | ||
loggedInUser: {} | ||
}); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { ApplicationRef, NgModuleRef } from '@angular/core'; | ||
import { Store } from '@ngrx/store'; | ||
import { createNewHosts, removeNgStyles } from '@angularclass/hmr'; | ||
|
||
import 'rxjs/add/operator/take'; | ||
|
||
|
||
// This variable will contain the application state after a module has been | ||
// unloaded. From here it is read to the next application version when it's | ||
// loaded (see app/app.module.ts). | ||
export let appState: any; | ||
|
||
// Called from main.ts when a hot bootstrap should be done. | ||
// This function is called every time the application loads | ||
// (first when the page loads, and then again after each hot reload) | ||
export function handleHmr( | ||
module: any, // The module that we're handling HMR for (it'll be the main.ts module) | ||
bootstrap: () => Promise<NgModuleRef<any>>) { // The bootstrap function (comes from main.ts) | ||
|
||
// Store a reference to the NgModule that we will bootstrap. | ||
// We'll need it during unload. | ||
let moduleRef: NgModuleRef<any>; | ||
|
||
// Bootstrap the module and grab the NgModule reference from the | ||
// promise when it's resolved. This will start the application. | ||
bootstrap() | ||
.then(mod => moduleRef = mod); | ||
|
||
// Let Webpack know that we can handle hot loading for this module | ||
module.hot.accept(); | ||
|
||
// Attach a callback to module unload. This'll be called during a hot | ||
// reload, before the new version of the application comes in. We need to: | ||
// 1) Grab the current state of the previous application so we can reuse it. | ||
// 2) Destroy the previous application so that the new one can load cleanly. | ||
module.hot.dispose(() => { | ||
// Grab a reference to the running Angular application. | ||
const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef); | ||
// Grab a reference to the application's @ngrx/store. | ||
const store: Store<any> = moduleRef.injector.get(Store); | ||
// Get the current state from the Store. The store is an Observable so | ||
// we can use the Observable API to get the state. We'll get it synchronously | ||
// though this code may look like we might not. | ||
store.take(1).subscribe(s => appState = s); | ||
|
||
// When an Angular app is destroyed, it will also remove the DOM elements | ||
// of its root component(s) from the page. When doing hot loading, this is | ||
// a problem because the next version of the app will have nothing to | ||
// attach to. We need to clone the DOM nodes of the current application's root | ||
// component(s) | ||
const cmpLocations = appRef.components.map(cmp => cmp.location.nativeElement); | ||
const disposeOldHosts = createNewHosts(cmpLocations); | ||
moduleRef.destroy(); | ||
removeNgStyles(); | ||
disposeOldHosts(); | ||
|
||
// After this, the next version of the app will load momentarily. | ||
// Webpack dev server will execute the new `main.ts` which will then call | ||
// `handleHmr` again... | ||
}); | ||
|
||
} |
Oops, something went wrong.