Проблема в том, что переменная ngrx не может использоваться вне тела селектора

#angular

Вопрос:

Проблема ngrx в том, что внутри тела селектора переменной в классе присваивается значение, но оно не может использоваться вне тела селектора

Компонент.ts

     export class ProfileComponent implements OnInit {
  @Input() loading: boolean=false;
  Profile= {} as  Profile;
  user = {} as User;
  data:any
  constructor(private store: Store<AppState>,
    private spinner: NgxSpinnerService) {
    this.store.select(getUser).subscribe((data:any)=>this.user=data);
    this.store.select(getloadingProfile).subscribe(data=>{
      this.spinner.show();
      if(!data){
      this.loading=data;
      this.spinner.hide();
    }});
      }
  ngOnInit() {
 this.store.select(getloadingProfile).subscribe((dataProfile:any)=> {
  this.Profile=dataProfile;
  console.log(this.Profile); //<--Here it prints the data inside the selector body
 });
console.log(this.Profile); //<--here does not print
}

}
 

это:
селектор.ts

  import { ProfileState } from '../state/Profile.state';
import { createFeatureSelector, createSelector } from '@ngrx/store';
import { selectAll } from '../reducers/Profile.reducers';

export const Profile_STATE_NAME = 'Profile';
const getProfileState = createFeatureSelector<ProfileState>(Profile_STATE_NAME);
export const getProfile = createSelector(getProfileState, selectAll);
export const getProfileEntities = createSelector(
  getProfileState,
  (state) => state.Profile
);
export const getloadingProfile = createSelector(getProfileState, (state) => state.ProfileLoaded);
export const selectProfileError = createSelector(getProfileState, (state) => state.error);
 

это:
Действие.ts

  import { EntityState, createEntityAdapter, EntityAdapter } from '@ngrx/entity';
import { ProfileModule } from 'src/app/profile/profile.module';
import { Profile } from '../../models/Profile.model';

export interface ProfileState extends EntityState<Profile> {
  ProfileLoaded: boolean;
  Profile:Profile;
  error: boolean;
}
export const ProfileAdapter: EntityAdapter<Profile> = createEntityAdapter<Profile>({
  selectId: (customer: Profile) => customer.id
});
export const initialState: ProfileState = ProfileAdapter.getInitialState({
  ProfileLoaded: true,
  error: false,
  Profile:{} as Profile
});
 

это:
состояние.ts

   import { EntityState, createEntityAdapter, EntityAdapter } from '@ngrx/entity';
import { ProfileModule } from 'src/app/profile/profile.module';
import { Profile } from '../../models/Profile.model';

export interface ProfileState extends EntityState<Profile> {
  ProfileLoaded: boolean;
  Profile:Profile;
  error: boolean;
}
export const ProfileAdapter: EntityAdapter<Profile> = createEntityAdapter<Profile>({
  selectId: (customer: Profile) => customer.id
});
export const initialState: ProfileState = ProfileAdapter.getInitialState({
  ProfileLoaded: true,
  error: false,
  Profile:{} as Profile
});
 

this is:
reducer.ts

  import {loadProfileSuccess,loadProfileFail,} from '../actions/Profile.actions';
import { createReducer, on } from '@ngrx/store';
import { initialState, ProfileAdapter } from '../state/Profile.state';
const _ProfileReducer = createReducer(
  initialState,
    on(loadProfileSuccess, (state, action) => ({
      ...state,
      Profile:action.profile,
      ProfileLoaded: false
    })),
  on(loadProfileFail, (state) => {
    return ProfileAdapter.removeAll({
      ...state,
      error: true,
      loading: false,
    });
  }),
);
export const { selectAll, selectIds } = ProfileAdapter.getSelectors();
export function ProfileReducer(state:any, action:any) {
  return _ProfileReducer(state, action);
}
 

это:
Эффект.ts

  @Injectable()
export class ProfileEffects {
  constructor(
    private actions$: Actions,
    private PagesService: PagesService,
  ) { }

  loadProfile$ = createEffect(() =>
    this.actions$.pipe(
      ofType(loadProfile),
      
      concatMap(() => this.PagesService.GetProfile()),
      map((Profile:Profile) => {
        return loadProfileSuccess({ profile:Profile })
      },
        catchError((error) => of(loadProfileFail(error))))
    )
  );
}
 

это:
решатель.ts

 @Injectable()
export class ProfileResolver implements Resolve<Observable<any>> {
  constructor(private store: Store<AppState>) { }
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
    return this.store
      .pipe(
        select(getloadingProfile),
        tap((loadProfileSuccess) => {
          if (loadProfileSuccess) {
            console.log(loadProfileSuccess);
            this.store.dispatch(loadProfile());
          }
        }),
        first()
      );
  }
}
 

Пожалуйста, помогите мне как можно скорее, спасибо

Комментарии:

1. Похоже, вы пытаетесь напечатать значение this.Profile до того, как ему будет присвоено значение. Можете ли вы попробовать распечатать его значение в крючке жизненного цикла ngAfterViewInit ()?

2. Наблюдаемый ваш селектор выдает события асинхронно, это означает, что ваш обратный вызов подписки не вызывается немедленно. В то время, когда вы попытаетесь распечатать свою переменную, которая на данный момент все еще не инициализирована, вы увидите пустой объект.

3. @Phalgun Он по-прежнему печатает пустое значение после того, как попробовал то, что вы сказали

4. @RomanP. Каково, пожалуйста, решение?

5. Для этого существует множество решений, одно из которых вы можете увидеть в моем ответе.

Ответ №1:

Если вы введете начальное состояние профиля с нулем, вы можете сделать что-то подобное:

 this.store.select(getloadingProfile).pipe(
  filter(Boolean),
  take(1),
).subscribe((profile) => console.log('Your Profile', profile));
 

Что бы подписаться на ваш observable, отфильтруйте начальное значение до тех пор, пока оно не будет инициализировано чем-то правдивым, затем оно примет первое излучение, распечатает его на консоли и отпишется.

Каждый раз, когда вы подписываетесь на наблюдаемое, вы также должны отказаться от подписки на него.

В первом примере оператор take откажется от подписки за вас.

Но я бы посоветовал вам работать с наблюдаемым в вашем шаблоне с помощью асинхронного канала, это позволит вам подписаться / отказаться от подписки.

напр.:

 <div *ngIf="ProfileObs$ | async as profile">
  <span>Name: {{ profile.name }}</span>
</div>
 

Комментарии:

1. Он по-прежнему не работает для обновления новых значений, но в шаблоне он отображает значения, но я не могу выполнить какую-либо операцию с предстоящими данными, потому что он дает нулевые значения. Есть ли какое-то решение? Я знаю, что устал от тебя

2. Какие ценности вы имеете в виду? Ваши локальные переменные вашего класса? Отправляете ли вы действие, которое вызывает ваш эффект? Есть ли правильные данные в вашем штате? Пример СтекбЛитца был бы хорош.

3. Спасибо, проблема решена. Проблема заключалась в том, что я использовал canActivate с решателем. Он был удален, может быть активирован, так как ему было разрешено перейти в компонент перед загрузкой данных профиля