2

I've been creating React Typescript app with RTK Query, and I want to implement custom selectors. But to implement it, I need to get some data from another endpoint:

store.dispatch(userApiSlice.endpoints.check.initiate(undefined))
const data = userApiSlice.endpoints.check.getSomeData

export const selectCartItemsResult = cartApiSlice.endpoints.getCartItems
  .select(data?.user?.id ?? skipToken)

I found solution here. Their solution looks like this:

class TodoService {
   getSelectorForTodo(todoId: string) {
     if (this._lastId !== todoId) 
       this._lastSelector = api.endpoints.getTodo.select( {id: todoId } )
     return this._lastSelector
   }

   getTodoTitle( todoId: string ) {
     const todo = this.getSelectorForTodo(todoId)(state)
     return todo.data.title
   }
}

I do not where to get the state variable. So I come with putting inside store.getState(), but this gives the following error:

const data = userApiSlice.endpoints.check
  .select(undefined)(store.getState())

-->

The types of 'api.queries' are incompatible between these types. Type 'QueryState<{ getCartItems: QueryDefinition<number, BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError, {}, FetchBaseQueryMeta>, "cart", EntityState<...>, "api">; clearCart: MutationDefinition<...>; addItem: MutationDefinition<...>; changeItemQuantity: MutationDefinition<...>; changeItemSize: MutationDefini...' is not assignable to type 'QueryState<{ registration: MutationDefinition<IRegisterBody, BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError, {}, FetchBaseQueryMeta>, "cart", IUserApiState, "api">; login: MutationDefinition<...>; check: QueryDefinition<...>; }>'.

I don't have another idea of how to get a state variable. Please, can you give some example that compiles with typescript but also declares the state variable?

I do not know what you need of all RTK Query implementation. So I will add it when needed

EDIT: cartApiSlice and userApiSlice were created with injectEndpoints.

Demian
  • 121
  • 3
  • 11

1 Answers1

2

Because your userApiSlice was injected into your api after your state was created, TypeScript can't know that something was added here - so it complains because the api "in the types" just doesn't have those extra endpoints.

That doesn't mean that it won't work though - it's just that TypeScript is complaining here.

You won't get around telling TypeScript "I know better than you" in this case - do an assertion as any.

const data = userApiSlice.endpoints.check
  .select(undefined)(store.getState() as any)
phry
  • 35,762
  • 5
  • 67
  • 81
  • I do like this: `store.dispatch(userApiSlice.endpoints.check.initiate(undefined)) .unwrap().catch(() => undefined) export const all = userApiSlice.endpoints.check .select(undefined)(store.getState() as any)` `all` in debugger shows: `endpointName: 'check' isError: false isLoading: true isSuccess: false isUninitialized: false requestId: 'stG-BTk2dgU41MaGCWXcm' startedTimeStamp: 1665573056482 status: 'pending'` – Demian Oct 12 '22 at 11:13
  • Interesting that `const data = await store.dispatch(userApiSlice.endpoints.check.initiate(undefined)) .unwrap().catch(() => undefined)` works. I just had to set `experiments.topLevelAwait: true` in my webpack config . Can I write it as an answer? – Demian Oct 12 '22 at 11:17
  • But the problem with my solution is when I register, it updates the token all good but does not update selectors. But with login, all work well. Do you have any idea? Or is it better to write another question? – Demian Oct 12 '22 at 11:24
  • 1
    Your code runs once and gets you a snapshot of the data at that time. You will need to add code subscribing to store changes and re-executing the selector every time that happens if you want that - that's what `react-redux` usually does for you. – phry Oct 12 '22 at 11:58
  • Sorry, I can't understand. Isn't `store.dispatch(userApiSlice.endpoints.check.initiate(undefined))` a subscription creator? – Demian Oct 12 '22 at 12:17
  • 1
    A subscription in the context of RTKQ means "someone is using that data right now, don't delete it from the cache until they unsubscribe". It won't magically update your variables for you. You want `store.subscribe` which will allow you to run a selector on every store change. Or, really, try to do this closer to a component or run the selector when you need that data. – phry Oct 12 '22 at 16:19
  • 1
    What does that in the context of react-redux is `useSelector`. It subscribes to the store and rerenders the component on each change. – phry Oct 12 '22 at 16:20
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/248765/discussion-between-demyan-netlyukh-and-phry). – Demian Oct 12 '22 at 17:55
  • 1
    Sorry I'm really not up for chatting right now. I would suggest you ask in the redux channel on the Reactiflux Discord as there are always people helping out there. – phry Oct 12 '22 at 19:32