Design and Implement Universal support. #3076
Replies: 28 comments
-
Spitballing an idea of how we might tackle this:
function universalMetaReducer(actionReducer) {
return function (state, action) {
if (action.type === 'REHYDRATE') {
return actionReducer(action.state, action);
}
return actionReducer(state, action);
}
}
import { isPlatformBrowser } from '@angular/common';
@Component({
template: `
{{ state$ | json }}
`
})
export class NgrxUniversalComponent {
state$: Observable<any>;
constructor(private elementRef: ElementRef, private store: Store<any>) {
if (isPlatformBrowser()) {
this.startRehydration();
}
else {
this.startSerialization();
}
}
startRehydration() {
try {
const state = JSON.parse(this.elementRef.nativeElement.innerText);
this.store.dispatch({ type: 'REHYDRATE', state });
this.state$ = Observable.empty();
} catch(e) { }
}
startSerialization() {
this.state$ = this.store;
}
} |
Beta Was this translation helpful? Give feedback.
-
update - @vikerman advises me that we should have a built in for transferState in platform-server in the next couple of weeks, and we'll build off that 👍 |
Beta Was this translation helpful? Give feedback.
-
I noticed that the snippets above use Over in #143 and #160 it sounds like there is work underway that will make many Actions will have symbols in them, and will depend on the Action being of a specific class, not just an Object with the right data in it. Both of those things require a more complex serialization approach. |
Beta Was this translation helpful? Give feedback.
-
@kylecordes I don't think you'd be transferring actions this way, so non-serializable actions are probably fine (in this context). State is the thing being transferred here, which should almost always be serializable (the router state issue notwithstanding)... |
Beta Was this translation helpful? Give feedback.
-
@kylecordes I don't believe #143 or #160 will be going into ngrx. Classes are only used for actions to reduce the boilerplate of building type unions and action creators. Serialization is still a major focus for ngrx. |
Beta Was this translation helpful? Give feedback.
-
@MikeRyanDev That makes sense, but reducing boilerplate is not the only thing classes are used for. They are also used for type inference via the But I don't see class based actions, which we already use, interfering with state rehydration in universal, as long as the state itself remains serializable. |
Beta Was this translation helpful? Give feedback.
-
@karptonite |
Beta Was this translation helpful? Give feedback.
-
Any updates on this? |
Beta Was this translation helpful? Give feedback.
-
@Flood |
Beta Was this translation helpful? Give feedback.
-
I also am very interesting in using this. stateTransfer object would replace initial state arg in the reducer function call? |
Beta Was this translation helpful? Give feedback.
-
any updates? im very interested to use this |
Beta Was this translation helpful? Give feedback.
-
@RSginer it's currently in design |
Beta Was this translation helpful? Give feedback.
-
@Toxicable okey thanks, if i can help you tell me! |
Beta Was this translation helpful? Give feedback.
-
StateTransfer API has been merged: angular/angular#19134 |
Beta Was this translation helpful? Give feedback.
-
This is in 5.0 RC now - https://next.angular.io/api/platform-browser/TransferState You would want to hook on to TransferState.onSerialize to the set the current state object just before the DOM is serialized on the server side. |
Beta Was this translation helpful? Give feedback.
-
Any updates on this? Is anyone working on it? |
Beta Was this translation helpful? Give feedback.
-
This is how I did it. // make sure you export for AoT
export function stateSetter(reducer: ActionReducer<any>): ActionReducer<any> {
return function(state: any, action: any) {
if (action.type === 'SET_ROOT_STATE') {
return action.payload;
}
return reducer(state, action);
};
}
const _metaReducers: MetaReducer<fromRoot.State, any>[] = [stateSetter];
if ( !environment.production ) {
_metaReducers.push( debugMetaReducer );
}
export const metaReducers = _metaReducers;
export const NGRX_STATE = makeStateKey('NGRX_STATE');
const modules = [
StoreModule.forRoot(fromRoot.reducers, { metaReducers }),
HttpClientModule,
RouterModule,
routing,
BrowserModule.withServerTransition({
appId: 'store-app'
}),
BrowserTransferStateModule,
];
const services = [
{
provide: RouterStateSerializer,
useClass: MyRouterStateSerializer,
}
];
const containers = [
AppComponent,
HomeComponent,
];
@NgModule({
bootstrap: [AppComponent],
declarations: [
...containers
],
imports: [
...modules,
BrowserModule.withServerTransition({ appId: 'store-app' }),
StoreRouterConnectingModule,
],
providers: [
...services,
],
})
export class AppModule {
public constructor(
private readonly transferState: TransferState,
private readonly store: Store<fromRoot.State>,
) {
const isBrowser = this.transferState.hasKey<any>(NGRX_STATE);
if (isBrowser) {
this.onBrowser();
} else {
this.onServer();
}
}
onServer() {
this.transferState.onSerialize(NGRX_STATE, () => {
let state;
this.store.subscribe( ( saveState: any ) => {
// console.log('Set for browser', JSON.stringify(saveState));
state = saveState;
}).unsubscribe();
return state;
});
}
onBrowser() {
const state = this.transferState.get<any>(NGRX_STATE, null);
this.transferState.remove(NGRX_STATE);
this.store.dispatch( { type: 'SET_ROOT_STATE', payload: state } );
// console.log('Got state from server', JSON.stringify(state));
}
} |
Beta Was this translation helpful? Give feedback.
-
@MattiJarvinen-BA Do you have any repo having the code base ? |
Beta Was this translation helpful? Give feedback.
-
@rijine everything related to transitioning server state to browser is in the code above. Basic angular server side render tutorials can be found on Angular.io https://angular.io/guide/universal |
Beta Was this translation helpful? Give feedback.
-
@MattiJarvinen-BA's solution is cool. I just wonder, when you use effects, wouldn't you rather set and retrieve the transfer state in the effect where you make the service calls to the API? |
Beta Was this translation helpful? Give feedback.
-
@renestalder I'm doing something like this to first check TransferState for data, then calling the service if there's nothing there.
|
Beta Was this translation helpful? Give feedback.
-
@kaitlynekdahl Nice, thanks. Will try to implement that in one general effect running before the other effects to only be needed doing it once. Where do you put |
Beta Was this translation helpful? Give feedback.
-
@renestalder that would be with Please do share your snippet when you got something to show. |
Beta Was this translation helpful? Give feedback.
-
please help with ngrx-router - I have router error with
|
Beta Was this translation helpful? Give feedback.
-
How would one solve this with the new creators syntax? Could not find any updated infos on that. Much appreciated |
Beta Was this translation helpful? Give feedback.
-
Hey @MattiJarvinen , want to know how should we handle the State that are |
Beta Was this translation helpful? Give feedback.
-
Based on the conversation, it seems NgRx is usable within Universal with some extra setup. Would it be a goal of the project to give Universal first-class support, or is the demonstrated user-land capability to integrate sufficient? |
Beta Was this translation helpful? Give feedback.
-
@david-shortman As Universal is a first-class, Angular-supported feature/tool, I think it would be great to have first-class support in NgRx. However, since that's probably not going to be trivial to include in a generic sort of way that would work in everyone's setups, I think it should just be noted in the NgRx docs (cleaned up examples would be ideal, but just with a link to this thread would be super-helpful). Right now, the silence in the docs make it seems to me like 1) it should work out of the box or 2) that it's just fully unsupported. Thanks! |
Beta Was this translation helpful? Give feedback.
-
Now 4.0 and Universal are out in the wild, we should see about making state hydration a bit simpler, and enabling developers to as automagically-as-possible transfer initial state from client -> server.
Beta Was this translation helpful? Give feedback.
All reactions