TypeError: 无法读取未定义的属性 ‘pipe’ Angular 14 与 NGRX

huangapple go评论89阅读模式
英文:

TypeError: Cannot read property 'pipe' of undefined Angular 14 with NGRX

问题

I receive the above error in my Effect, and I cant see why.

Here is my effect:

login$ = createEffect(
() =>
this.actions$.pipe(
ofType(fromAuthActions.login),
switchMap((auth) => {
return this.authService.doLogin(auth.email, auth.password)
.pipe(map((data) => fromAuthActions.loginComplete({ profile: data, isLoggedIn: true })))
})
),
{ dispatch: false }
);

here are my two actions:

export const login = createAction('[Auth] login', props<{ email: string, password: string }>());

export const loginComplete = createAction(
'[Auth] loginComplete',
props<{ profile: LoggedInUser; isLoggedIn: boolean }>()
);

My reducer, where profile is declared LoggedInUser | null

on(authActions.loginComplete, (state, { profile, isLoggedIn }) => {
return {
...state,
profile,
isLoggedIn,
};
}),

and my Service that makes the call to the server (I get to the server and I can see via the Network tab in the browser, that the server is returning the correct data).

doLogin(email: string, password: string): any {
let user: LoginUser = {
email: email,
password: password,
};
var returnval = this.crud.post(user, 'Auth/login');
returnval.subscribe((e: LoggedInUser) => { return e; });

}

I think my issue is that on my doLogin method my return type is any and so in my effect data passed back is of type any but I'm strongly typing data to LoggedInUser as that is what I really want. Also, I'm not sure about the Subscribe in my doLogin method, but if I don't have it there, then the server does not get called.

I am struggling to get this right. Any help greatly appreciated.

英文:

I receive the above error in my Effect, and I cant see why.

Here is my effect:

login$ = createEffect(
    () =&gt;
      this.actions$.pipe(
        ofType(fromAuthActions.login),
        switchMap((auth) =&gt; {
          return this.authService.doLogin(auth.email, auth.password)
            .pipe(map((data) =&gt; fromAuthActions.loginComplete({ profile: &lt;LoggedInUser&gt;data, isLoggedIn: true })))
        })
      ),
    { dispatch: false }
  );

here are my two actions:

export const login = createAction(&#39;[Auth] login&#39;, props&lt;{ email: string, password: string }&gt;());

export const loginComplete = createAction(
  &#39;[Auth] loginComplete&#39;,
  props&lt;{ profile: LoggedInUser; isLoggedIn: boolean }&gt;()
);

My reducer, where profile is declared LoggedInUser | null

on(authActions.loginComplete, (state, { profile, isLoggedIn }) =&gt; {
    return {
      ...state,
      profile,
      isLoggedIn,
    };
  }),

and my Service that makes the call to the server (I get to the server and I can see via the Network tab in the browser, that the server is returning the correct data).

doLogin(email: string, password: string): any {
    let user: LoginUser = {
      email: email,
      password: password,
    };
    var returnval = this.crud.post&lt;LoggedInUser&gt;(user, &#39;Auth/login&#39;);
      returnval.subscribe((e: LoggedInUser) =&gt; { return e; });

  }

I think my issue is that on my doLogin method my return type is any and so in my effect data passed back is of type any but I'm strongly typing data to LoggedInUser as that is what I really want. Also, i'm not sure about the Subscribe in my doLogin method, but if I dont have it there, then the server does not get called.

I am struggling to get this right. any help Greatly appreciated.

答案1

得分: 2

doLogin 方法存在问题:

  doLogin(email: string, password: string) {
    let user: LoginUser = {
      email: email,
      password: password,
    };

    return this.crud.post<LoggedInUser>(user, 'Auth/login');
  }

修复后,doLogin 方法将返回实际的 Observable,可以在你的效果中使用 pipe

额外信息:

.subscribe 立即启动 Observable,如果您不订阅它,服务器将不会被调用。对于 ngrx effects,您不需要立即订阅任何内容。

login$ Observable 实际上是一个组合的 Observable,它监听所有操作,但只在发出“login”操作时发出内容。这是通过 ofType(fromAuthActions.login), 完成的。

当您发出类型为 fromAuthActions.login 的操作(通过在某处调用 store.dispatch(login(...)))时,login$ Observable 将切换到另一个 Observable,即this.authService.doLogin 返回的 Observable。这就是 switchMap 操作符的作用,这也是为什么需要从 doLogin 返回一个 Observable:您希望 login$ 切换到新的 Observable 以启动 POST 请求。

doLogin 返回的 Observable 将再次使用 pipe,这次返回另一个操作 - 这是 ngrx effects 预期的内容。NGRX 将知道如何在另一个 effect 中解释新的操作("login complete")。

英文:

The problem is with your doLogin implementation:

  doLogin(email: string, password: string): any {
    let user: LoginUser = {
      email: email,
      password: password,
    };
    var returnval = this.crud.post&lt;LoggedInUser&gt;(user, &#39;Auth/login&#39;);
      returnval.subscribe((e: LoggedInUser) =&gt; { return e; });

  }

Here, returnval does nothing, and doLogin does not return anything - hence your error message: a function that returns nothing will implicitly return undefined.

I believe you intended to actually return the observable that crud.post creates.

  doLogin(email: string, password: string) {
    let user: LoginUser = {
      email: email,
      password: password,
    };

    return this.crud.post&lt;LoggedInUser&gt;(user, &#39;Auth/login&#39;);
  }

Like this, doLogin will return the actual Observable, which in turn can be piped within your effect.

Tip: never type your functions to return any. This will allow typescript to detect when you made such a mistake early on.


Extra info

> Also, i'm not sure about the Subscribe in my doLogin method, but if I dont have it there, then the server does not get called.

.subscribe starts the observable immediately, that's why your server isn't called if you never subscribe to it. Observables do not execute unless something subscribes to them; however for ngrx effects you don't want to subscribe to anything immediately.

Your login$ observable is actually a composed observable that listens to all actions, but it filters out to only emit something if the login action was emitted. This is done by the line ofType(fromAuthActions.login),.

When you emit an action of type fromAuthActions.login(by calling store.dispatch(login(...)) somewhere), the login$ observable will then switch to another observable - the one returned by this.authService.doLogin. This is what the switchMap operator is for, and this is why you need to return an observable from doLogin: you want to have login$ switching into the new observable in order to kick off your POST request.

The Observable returned by doLogin will then be piped again, this time returning another action - which is what ngrx effects expect. NGRX will know to interpret the new action("login complete") in another effect.

huangapple
  • 本文由 发表于 2023年4月11日 01:48:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/75979429.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定