Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: More verbose error message for unprovided feature state in development mode #1897

Closed
1 of 2 tasks
jtcrowson opened this issue May 28, 2019 · 25 comments · Fixed by #2078
Closed
1 of 2 tasks

RFC: More verbose error message for unprovided feature state in development mode #1897

jtcrowson opened this issue May 28, 2019 · 25 comments · Fixed by #2078
Labels
Need Discussion Request For Comment needs input

Comments

@jtcrowson
Copy link
Contributor

jtcrowson commented May 28, 2019

TL;DR: Add helpful error in development mode when the developer attempts to access feature state that has not been provided.

As a newer NgRx developer, I occasionally had a bug where I was attempting to access state via a selector, but got a console error ERROR TypeError: Cannot read property 'books' of undefined. The issue was, I was using the selector in a module in the app where the StoreModule had not yet been provided with the feature state via StoreModule.forFeature('books', reducers). This module was usually accessed after navigating to another page first, who's module provided the correct feature state, so it was hard to track down.

My proposal is to add a more verbose error message in development mode at the createFeatureSelector level to provide some insight to the developer that they likely did not provide the feature State.

Proposed solution

export function createFeatureSelector<T>(
  featureName: string
): MemoizedSelector<object, T>;
export function createFeatureSelector<T, V>(
  featureName: keyof T
): MemoizedSelector<T, V>;
export function createFeatureSelector(
  featureName: any
): MemoizedSelector<any, any> {
  return createSelector(
    (state: any) => {
      const featureState = state[featureName];
      if (isDevMode() && featureState === undefined) {
        console.error(`The feature name \"${featureName}\" does not exist in the state's root, therefore createFeatureSelector cannot access it.  Be sure it is imported in a loaded module using StoreModule.forRoot(\'${featureName}\', ...) or StoreModule.forFeature(\'${featureName}\', ...).`);
      }
      return featureState;
    },
    (featureState: any) => featureState
  );
}

If accepted, I would be willing to submit a PR for this feature

  • Yes (Assistance is provided if you need help submitting a pull request)
  • No
@brandonroberts
Copy link
Member

This could also be a false positive in the case of using router-store where everything is connected correctly, but the state isn't populated until the first router event happens.

@jtcrowson
Copy link
Contributor Author

Would the developer get an error about the undefined property in that case?
ERROR TypeError: Cannot read property 'router' of undefined

@brandonroberts brandonroberts added the Need Discussion Request For Comment needs input label Jun 3, 2019
@evgenyfedorenko
Copy link
Contributor

Maybe there should be more generic message then which covers the router case too ?

@jtcrowson
Copy link
Contributor Author

Definitely should make the message more generic. I think any error raises suspicion, so even getting a ERROR TypeError: Cannot read property 'router' of undefined because the router state isn't populated is helpful so devs don't think there's an issue. Also, think it makes sense to limit the error to non-production builds only.

@evgenyfedorenko
Copy link
Contributor

So this is a non blocking error? Store can recover from it easily?

@jtcrowson
Copy link
Contributor Author

Well in the case of router-state, store is fine. But the most common case, the store has not yet been set up but it is trying to be accessed.

@jtcrowson jtcrowson changed the title RFC: More verbose error message for unprovided feature state RFC: More verbose error message for unprovided feature state in development mode Jun 18, 2019
@timdeschryver
Copy link
Member

I'm not certain but would this give errors because of the isDevMode() mode?

@jtcrowson
Copy link
Contributor Author

jtcrowson commented Jun 19, 2019

@timdeschryver It should not give errors, because the block of code containing isDevMode() would get executed by the application itself, guaranteeing it is not executed until after the application has been initialized. Tested it to verify as well 👍

@jtcrowson
Copy link
Contributor Author

@brandonroberts could I get more information on the router-state? I was unable to reproduce. Would the user still get an undefined error? Do we think this message would be worth adding in development?

@timdeschryver
Copy link
Member

timdeschryver commented Jun 26, 2019

(sorry to interrupt)
@jtcrowson the router reducer doesn't have an initial state (so it's still undefined) and will create new state on each navigation. https://github.com/ngrx/platform/blob/master/modules/router-store/src/reducer.ts#L21

Thus the selector will first receive the undefined state (because this is before the first navigation), resulting in the message being logged.

@kubk
Copy link

kubk commented Aug 4, 2019

Just encountered this error because of a typo. Would be nice to have it fixed.

@jtcrowson
Copy link
Contributor Author

I'm still in favor of moving forward with this error message in development mode only. I can note that this error is not an issue for router state. Thoughts @brandonroberts @timdeschryver? I think it also helps in case of the router state, since an error is already being logged without explanation.

@brandonroberts
Copy link
Member

I think there is less value in this due to #2017, but it could provide some helpfulness.

@jtcrowson
Copy link
Contributor Author

Agreed, the typo cause should hopefully be less common. For me, this is more about accidentally not registering the state all together but trying to access a selector.

@brandonroberts
Copy link
Member

👍🏿

@Halt001
Copy link

Halt001 commented Sep 10, 2019

Is there any way to suppress this warning specific for the router state? Having warnings that one should always ignore is not good practice imho.

@Halt001
Copy link

Halt001 commented Sep 11, 2019

Our unit test output is now littered with lots of this warning complaining about the undefined router in the state. This totally wrecks our unit test output.

image

@timdeschryver
Copy link
Member

@Halt001 could you create a new issue please?

@meanstack-perficient
Copy link

meanstack-perficient commented Sep 25, 2019

actually this error produces the undefined message stated above
yes I am receiving the type error

and takes out the ngrx store itself

so this breaks ngrx feature state (just a spinner) in my case

i remodeled my feature state and selectors... blue in the face

cant shake it

can someone escalate this, reopen or provide workaround

/vendor.js:197218 The feature name "feature" does not exist in the state, therefore createFeatureSelector cannot access it. Be sure it is imported in a loaded module using StoreModule.forRoot('feature', ...) or StoreModule.forFeature('feature', ...). If the default state is intended to be undefined, as is the case with router state, this development-only warning message can be ignored.

ERROR TypeError: Cannot read property 'spinner' of undefined

@jtcrowson
Copy link
Contributor Author

@meanstack-perficient This error doesn't provide any different behavior for NgRx, all it does is produce a warning if your state hasn't been initialized. Are you sure this warning isn't correctly alerting you to a problem where your state isn't provided?

@meanstack-perficient
Copy link

thanks jt

what i have been seeing in the field are angular component developers are creating components that are bloated and case logic is excessive to the point where managing an aggressive angular project becomes unmanagable and unresponsive to velocity.

so I am boilerplating all my talks to service layer in ngrx

which means alot of modules

what I also observed in the field, these angular components talking to the back end with no state mgt or boilerplating is utterly littered with async threads of execution calls, init, etc... causing multithreaded contention especially when trying to introduce more module oriented scaffold

my scaffold houses 4 main large modules core, feature, biz and shared

it sits on ionic which forces the app to slide into tabs.module and lazyload all its dependent tab modules

but the lazy loading is presenting an even more async contention so I am trying to leave out any lazy loading to have something reasonably predictable for getting the app up on its feet

so yes your point is valid, something dependent in my modules isnt being initialized at the proper time and im sifting thru the modules as they pertain to the init load phase

I do have a nice ngrx spinner that starts running on boot so that likes to run in the midst of boot also

but Im not as impressed with the lazy loading and the async contention overall due to the race to initialize everything

so I get that warning

and after that if my ngrx state is not initialize properly I get the error

and I kinda felt maybe ngrx or angular could be more adaptable

but it seems I am caught up in the race condition thing of initialization

Im sifting thru it now

it may not be a bug, I will now shortly when I stabilize my scaffold

@aahmyu
Copy link

aahmyu commented Sep 27, 2019

Can you please provide a way to disable this "feature". The console in the dev tools is full of these warnings and it makes my life harder.

@Klaster1
Copy link

Klaster1 commented Oct 3, 2019

@dezmon-fernandez
Copy link

Agreed please provide a way to suppress these messages, our app relies on dynamic reducers via store.addReducer, since we can have x number of sources at any time. Plus unit test litter is no bueno

@Halt001
Copy link

Halt001 commented Oct 12, 2019

Work is already being done, see here:
#2163

jordanpowell88 added a commit to jordanpowell88/platform that referenced this issue Nov 8, 2019
ActionType is useful for extracting the response type of the new action creators.

feat(store): add verbose error message for undefined feature state in development mode (ngrx#2078)

Closes ngrx#1897

docs(store-devtools): add recipe to exclude store-devtools from the build (ngrx#2073)

Closes ngrx#1521

fix(store): add DefaultProjectorFn to public API (ngrx#2090)

Allows you to fully type the selector without reaching into the src folder

ci: fix filters on tags for publishing to npm and deployment of docs (ngrx#2091)

* refactor(data): use createEffect function instead of @effect decorator
jordanpowell88 pushed a commit to jordanpowell88/platform that referenced this issue Nov 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Need Discussion Request For Comment needs input
Projects
None yet
10 participants