I have an angular5 component that I am trying to hookup with a reduxstore, it looks like this:
import { Component } from '@angular/core';
import { NgRedux, select, DevToolsExtension } from '@angular-redux/store';
import { TodoActions } from './actions';
import { AppState, INITIAL_STATE, rootReducer } from './store';
import {Observable} from "rxjs/Observable";
@Component({
selector: 'app-root',
template: `
<input type="text" #edit />
<button (click)="actions.add({data:edit,action:'ADD'})">add</button>
<p>The list is:</p>
<ul>
<li *ngFor="let item of (items | async)">
{{item}}
</li>
</ul>
`,
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
@select() readonly items$: Observable<string[]>;
constructor(
ngRedux: NgRedux<AppState>,
devTools: DevToolsExtension,
private actions: TodoActions) {
ngRedux.configureStore(
rootReducer,
INITIAL_STATE,
null,
devTools.isEnabled() ? [ devTools.enhancer() ] : []);
}
}
The issue is that I cannot display items in the list. Here is the rootreducer:
import {Action} from 'redux';
import {TodoActions} from './actions';
export interface AppState {
items: string[];
}
export const INITIAL_STATE: AppState = {items: []};
export function rootReducer(state: AppState, action: Action): AppState {
switch (action.type) {
case TodoActions.ADD:
var newstate = state;
newstate.items.push(action.data.data.value);
return newstate;
}
;
default:
return state;
}
}
How can I display the items? it looks like the first item gets added to the state from the redux-console. Here is also a githublink
This doesn't look quite right:
var newstate = state;
newstate.items.push(action.data.data.value);
return newstate;
You're not actually creating a new array or a copy: both newstate
and state
are the same array, so you're probably better off returning a new array shallow-cloned:
export function rootReducer(state: AppState, action): AppState {
switch (action.type) {
case TodoActions.ADD:
return {
...state,
items: [
...state.items,
action.data.value
]
}
default:
return state;
}
}
You might notice I've pulled the type specifier off action
. I'm not sure it makes sense to specify Action
as the type for action, in most sample code I've seen that passed untyped so:
export function rootReducer(state: AppState, action): AppState {
This will avoid TS complaining about lack of data
on type Action
. Alternatively, you could define a custom action type for each reducer you write.
Once you get past that, I think the reason you're not seeing any items is because you name the array items$
in the @select
decorator. So:
@Component({
selector: 'app-root',
template: `
<input type="text" #edit />
<button (click)="actions.add({value:edit.value,action:'ADD'})">add</button>
<p>The list is:</p>
<ul>
<li *ngFor="let item of (items$ | async)">
{{item}}
</li>
</ul>
`,
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
@select() readonly items$: Observable<string[]>;
works better. Note I tweaked the button definition a bit to avoid passing the entire input through, since you only need the value
.