如何从 ngrx 存储中获取值到我的模板中?

How do I get the value from an ngrx store into my template?

这里完全是 Redux 菜鸟,我在将数据从商店中取出以便在我的视图中使用时遇到了一些困难。这是我的 Actions、Reducers 等

genre.model.ts

export interface Genre {
    id: string;
    title: string;
    description: string;
    slug: string;
    error: string;
}

export const initialState: Genre = {
    id: '',
    title: '',
    description: '',
    slug: '',
    error: null
};

genre.service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Http } from '@angular/http';
import {environment} from "../../../environments/environment";
import {Genre} from "./genre.model";

@Injectable()
export class GenreService {

    apiUrl = environment.apiUrl + environment.apiVersion + '/';

    constructor(private http: Http) { }

    /**
     * Gets Genres
     *
     * @returns {Observable<Genre[]>}
     */
    getGenres(): Observable<Genre[]> {
        return this.http.get(this.apiUrl + 'genres/')
            .map(res => res.json());
    }

    /**
     * Gets an individual genre
     *
     * @param {String} slug
     * @returns {Observable<Genre[]>}
     */
    getGenre(slug: String): Observable<Genre[]> {
        return this.http.get(this.apiUrl + 'genres/' + slug)
            .map(res => res.json().genre);
    }
}

genre.actions.ts

import { Action } from '@ngrx/store';
import { Injectable } from '@angular/core';

import { Genre } from '../_shared/genre.model';

@Injectable()
export class GenreActions {

    static LOAD_GENRES = '[Genre] Load Genres';
    loadGenres(): Action {
        return {
            type: GenreActions.LOAD_GENRES
        };
    }

    static LOAD_GENRES_SUCCESS = '[Genre] Load Genres Success';
    loadGenresSuccess(genres): Action {
        return {
            type: GenreActions.LOAD_GENRES_SUCCESS,
            payload: genres
        };
    }

    static GET_GENRE = '[Genre] Get Genre';
    getGenre(slug): Action {
        return {
            type: GenreActions.GET_GENRE,
            payload: slug
        };
    }

    static GET_GENRE_SUCCESS = '[Genre] Get Genre Success';
    getGenreSuccess(genre): Action {
        return {
            type: GenreActions.GET_GENRE_SUCCESS,
            payload: genre
        };
    }
}

genre.reducers.ts

import { Action } from '@ngrx/store';

import {Genre, initialState} from '../_shared/genre.model';

import { GenreActions } from './genre.actions';

export function genreReducer(state: Genre = initialState, action: Action) {
    switch (action.type) {
        case GenreActions.GET_GENRE_SUCCESS: {
            return action.payload;
        }
        case GenreActions.LOAD_GENRES_SUCCESS: {
            return action.payload;
        }
        default: {
            return state;
        }
    }
}

genre.effects.ts

export class GenreEffects {
    constructor (
        private update$: Actions,
        private genreActions: GenreActions,
        private svc: GenreService,
    ) {}

    @Effect() loadGenres$ = this.update$
        .ofType(GenreActions.LOAD_GENRES)
        .switchMap(() => this.svc.getGenres())
        .map(genres => this.genreActions.loadGenresSuccess(genres));

    @Effect() getGenre$ = this.update$
        .ofType(GenreActions.GET_GENRE)
        .map(action => action.payload)
        .switchMap(slug => this.svc.getGenre(slug))
        .map(genre => this.genreActions.getGenreSuccess(genre));
}

genre.detail.component.ts

import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import { ActivatedRoute, Router } from '@angular/router';
import { Component, OnInit } from '@angular/core';

import { Genre } from '../_shared/genre.model';
import { GenreActions } from '../_store/genre.actions';

@Component({
    selector: 'app-genre-detail',
    templateUrl: './genre-detail.component.html',
    styleUrls: ['./genre-detail.component.scss']
})
export class GenreDetailComponent implements OnInit {

    public idSub: Subscription;
    public genre: Observable<any>;

    constructor(
        private store: Store<Genre>,
        private route: ActivatedRoute,
        private genreActions: GenreActions,
        private router: Router
    ) {
        this.genre = store.select('genres');
    }

    ngOnInit() {
        this.idSub = this.route.params.subscribe(params => {
            this.store.dispatch(this.genreActions.getGenre(params['slug']));
            console.log(this.genre);
            });
    }
}

我可以看到我的 API 请求被触发了,它是 return 数据,我可以在 Redux devtools 中看到状态正在被填充,但我似乎无法使用正常的 {{ genre.title }} 将数据取出并放入我的视图中 我只是得到 [Object object] 被扔回给我?

我确信这可能真的很简单,但就像我说的那样,我是一个完全的菜鸟,并且已经花了大约 5 个小时来按照不同的教程等尝试不同的东西。

我猜你的流派是数组列表

线框图应该是这样的吧

genre : any ;

ngOnInit(){
 this.idSub = this.route.params.subscribe(params => {
   this.store.dispatch(this.genreActions.getGenre(params['slug']));
   });
   this.store.select('genres').subscribe(data => this.genre = data)
}

如果你想查看 ngrx 4,请看这个 link

我刚刚找到了我的 git 你可以查看我使用 ngrx v2 的回购快照。我没有相同的工作示例,但请放心,代码可以工作 LINK

更新

为 Genre 创建一个不同的对象以在状态下使用 Genre 接口

export interface AppState {
    genre:Genre
}

现在在构造函数或ngOnInit中订阅这个状态对象流派

private store: Store<AppState>, 
private route: ActivatedRoute, 
private genreActions: GenreActions, 
private router: Router 
) { 
this.store.select('genre').subscribe(data => this.genre = data); 
}

目前,您得到的只是 Observable,但需要的是流派列表。而且,这就是问题所在。您需要订阅它才能获得价值。

为 Genre 创建一个不同的对象以在状态下使用 Genre 接口(正如 Rahul Singh 已经说过的那样)

export interface AppState {
    genre:Genre
}

constructor(private store: Store<AppState>,
    private route: ActivatedRoute,
    private genreActions: GenreActions, 
    private router: Router) {}

并在 ngOnInit 中订阅它以观察更改。

ngOnInit(): void {
    this.store.select(s => s.genre).subscribe(data => this.genre = data);
}

注意ngOnInit()用于确保您使用的组件的属性(例如:@Input() someId: number)已经初始化。因此,如果您使用任何组件属性,您应该在 ngOnInit() 中使用。否则 constructor() 就可以了。 但是我们应该使用 constructor() 来设置依赖注入而不是其他。 ngOnInit() 比 "start" 更好 - where/when 组件的绑定已解析。