【问题标题】:Angular NGRX getting error when dispatching to state分派到状态时,Angular NGRX 出错
【发布时间】:2020-04-07 19:22:21
【问题描述】:

我第一次使用 Ngrx,虽然它相对简单,但在调度状态时出现错误。当用户打开应用程序时,他需要输入他的姓名并提交,下一个屏幕应该显示“问候{{用户名}}”。用户提交后,我收到此错误--> core.js:6014 ERROR TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))

感谢您的帮助

import { Action } from '@ngrx/store';
import { UserName, WishListItem } from 'src/model/name.model';

export enum AddToStateActionType{
    ADD_NAME = '[ADD_NAME] add name',
    ADD_TO_WISHLIST = '[ADD_TO_WISHLIST] add to wishlist'
}

export class AddWelcomeNameAction implements Action {
    readonly type = AddToStateActionType.ADD_NAME;

    constructor(public payload: UserName){}
}

export class AddToWishList implements Action {
    readonly type = AddToStateActionType.ADD_TO_WISHLIST;

    constructor(public payload: WishListItem){}
}

export type UserAction = AddWelcomeNameAction | AddToWishList ;

<!--Reducer-->

import {AddToStateActionType, UserAction} from './../action/action';
import { UserName, WishListItem } from 'src/model/name.model';

const initialState: any = {
    name: '',
    wishlist: []
};


export function reducer(state: any = initialState, action: any) {
    switch(action.type) {
        case AddToStateActionType.ADD_NAME:
            return [...state, action.payload.name];
        case AddToStateActionType.ADD_TO_WISHLIST:
            return [...state. action.payload.wishlist];
    default:
        return state;
    }
}

<!--AppState-->

import { UserName, WishListItem } from 'src/model/name.model';

export interface AppState {
    readonly username: UserName;
    readonly wishlist: Array<WishListItem> ;
  }

<!--Welcome component-->

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '../app.state/app.state';
import * as Actions from '../../action/action';
import {Router} from '@angular/router';
import { UserName } from 'src/model/name.model';

@Component({
  selector: 'app-welcome',
  templateUrl: './welcome.component.html',
  styleUrls: ['./welcome.component.css']
})
export class WelcomeComponent implements OnInit {
  userName: UserName = {name: ''};

  profileForm = new FormGroup({
    userName: new FormControl(''),
  });
  constructor(private store: Store<AppState>, private router: Router) { }

  ngOnInit() {
  }

  onSubmit() {
   this.store.dispatch(new Actions.AddWelcomeNameAction({name: this.profileForm.value}));
   this.router.navigate(['/search']);
  }

}

【问题讨论】:

  • 看起来像扩展运算符 ... 中的问题你可以在减速器返回之前添加 console.log(state) 吗?你能看到什么?
  • 返回空状态:{name: "", wishlist: Array(0)}

标签: angular ngrx ngrx-store


【解决方案1】:

您的状态类型不一致。 initialState 是对象,但 reducer 返回数组。如果您在控制台中尝试此代码,您会得到相同的错误:

const a = {name: "", wishlist: []}
const b = [...a]

TypeError: a is not iterable

【讨论】:

  • 你是对的。我将其更改为: return {...state, name: action.payload.name}; case AddToStateActionType.ADD_TO_WISHLIST: return {...state, wishlist: action.payload.wishlist};默认:返回状态;现在我没有收到任何错误并且仍然出现名称:(在接收组合中)this.store.select(store => this.name = store.username); HTML : 你好 {{name}}
【解决方案2】:

这两种情况的问题都出在你的减速器上。

在您的代码中:

export function reducer(state: any = initialState, action: any) {
    switch(action.type) {
        case AddToStateActionType.ADD_NAME:
            return [...state, action.payload.name];
        case AddToStateActionType.ADD_TO_WISHLIST:
            return [...state. action.payload.wishlist];
    default:
        return state;
    }
}

您错误地应用了扩展运算符,导致两个问题:

数组扩展运算符:您正在应用数组扩展运算符:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

[...state, action.payload.name]; // This is an array

这个算子的工作方式如下:

let a = [1, 2, 3];
let b = 4;
let c = [...a, b]; // Here we will add each item of a and then b resulting in c = [1, 2, 3, 4]

因此,运行时将尝试“迭代”状态,但状态是一个对象,而不是一个数组。这是第一个错误。

Reducer 返回类型:在默认情况下,您将按预期返回原始状态,但在这两种情况下,您实际上都返回了一个数组。

作为一个好习惯,如果你明确指定 reducer 的返回类型,你会看到 TypeScript 是如何抱怨它的。

解决方案: 要修复您的代码,您应该将您的 reducer 重写为:

case AddToStateActionType.ADD_NAME:
    // Here you return a copy of state and overwrite the name property.
    return { 
        ...state,
        name: action.payload.name,
    };
case AddToStateActionType.ADD_TO_WISHLIST:
    // Here you return a copy of state and overwrite the wishlist property with the same elements + the new one.
    return {
        ...state,
        wishlist: [...state.wishlist, action.payload.wishlist]
    };

【讨论】:

  • 你是绝对正确的。我现在完全可以理解我的错误了。尽管我使用了您的代码,但仍然出现错误。 return { ...state, state.name: action.payload.name, };错误在 state.name 和 state.wishlist 上
  • @Shira 哦对不起,我的错,你需要指定属性,而不是状态的值。我马上改正错误!
  • 太棒了!现在没有错误。最后一件事,当我试图显示 state.name 时,它​​什么也没显示: this.store.select(store => this.name = store.name);在 HTML 上:“Hello {{name}}”保持空白
  • NGRX 中的 @Shira 选择器是 Observables,它至少在您 .subscribe() 之前不会执行您的语句。另外,你必须改变它。我建议你通读这个ngrx.io/guide/store/selectors
  • @Shira:另外,如果您发现答案有用并且它解决了您的问题,您能否帮我回复一下并将其标记为解决方案? :)
猜你喜欢
  • 1970-01-01
  • 2017-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-18
  • 2019-03-16
相关资源
最近更新 更多