0

I have a component that use redux toolkit query useGetUserQuery('id') and loading state is handled with isLoading property but I hear that suspense is better for showing a loading screen when requesting an async data.

first, is that true ?

second,
I tried to use it but did not work can any one help me with that ?

App.tsx file

import { Suspense, useState } from 'react'
import api from './api'
import { useDispatch } from 'react-redux'
import User from './User'
import LoadingSpiner from './loadingSpiner'

function App() {
  const dispatch = useDispatch()
  return (
    <>
      <Suspense fallback={<LoadingSpiner />}>
        <User id='3' />
        <div className='w-full flex content-center my-3'>
          <button
            className='w-3/4 sm:w-1/2 md:w-1/4 lg:w-1/5 bg-green-600 p-3 rounded-xl hover:-translate-y-1 hover:cursor-pointer transition-all hover:shadow-green-800 hover:shadow-md mx-auto text-center'
            onClick={e => dispatch(api.util.resetApiState())}>Reset</button>
        </div>
      </Suspense>
    </>
  )
}

export default App

The user component

import { useGetUserQuery } from "./api"

type Props = {
    id: string
}

export const User = ({ id }: Props) => {
    const { data, isLoading } = useGetUserQuery(id)

    return (
        <>
            <div className="flex justify-center content-center py-3 bg-gray-200">
                <div className="border border-gray-500 p-3 rounded-s-xl">{isLoading ? 'Loading...V2 from user component' : (data && data.name)}</div>
            </div>
        </>
    )
}
export default User

is always show Loading...V2 from user component not the loading spine

so I really don't have any idea what is the wrong with it

edit:

apiSlice

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export interface User {
    id: number
    name: string
    username: string
    email: string
    address: Address
    phone: string
    website: string
    company: Company
  }
  
  export interface Address {
    street: string
    suite: string
    city: string
    zipcode: string
    geo: Geo
  }
  
  export interface Geo {
    lat: string
    lng: string
  }
  
  export interface Company {
    name: string
    catchPhrase: string
    bs: string
  }
  
const api = createApi({
  reducerPath: 'api',
  baseQuery: fetchBaseQuery({ baseUrl: 'https://jsonplaceholder.typicode.com/' }),
  endpoints: (builder) => ({
    getUser: builder.query<User,string>({
      query: (id) => `users/${id}`,
    }),
  }),
});

export const { useGetUserQuery } = api;
export default api;

Store

import { configureStore } from '@reduxjs/toolkit'
import api from './api'

const store = configureStore({
  reducer: {
    [api.reducerPath]: api.reducer
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(api.middleware)
});

export default store

Main.tsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { Provider } from 'react-redux'
import store from './store'
import './index.css'
import './tailwind.css'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
)
  • The `isLoading` status is for "Query is currently loading for the first time. No data yet." Are you sure your query is working correctly as expected? It might be relevant to [edit] the post to include your api slice code as part of a complete [mcve]. The `Suspense` doesn't work well because you aren't lazily loading any React UI, so there's nothing to "suspend" and wait for. – Drew Reese May 27 '23 at 07:38
  • ok i add it but the react.lazy I heard that is not important here because rtkquery handle it ? but i use it but throws an error @DrewReese – mahmoud2 nasser2 May 28 '23 at 03:44
  • I've copy pasted your code into a running [codesandbox](https://codesandbox.io/s/why-doesnt-react-suspense-work-properly-with-redux-toolkit-query-s41kmn) and the query appears to fetch and load data as I'd expect it to. It's unclear what the issue might be on your end, so all I can say is that if the `isLoading` state is always true then it seems the query is loading and never completes the initial loading. Check that the API request is made and validate how it settles. – Drew Reese May 28 '23 at 08:40
  • no, you miss understand me, I did not mean that `isLoading` state is always false but it will be true and the data will be gotten my question is about the loading screen that is rendered is the return of the check of `isLoading` in `if (isLoading)` in `User` component rather that the `LoadingSpiner` component which in `}>` and in your example in code sand box the loading screen is loadingv2.from user component not the spinner you did you got it ? and Thanks for trying, I appreciate that @DrewReese – mahmoud2 nasser2 May 29 '23 at 08:47
  • Did I not already address the suspense part in my initial comment? Suspense doesn't do anything because there's nothing being lazily loaded. The `'Loading...V2 from user component'` in the `User` component is the only loading UI that will render. – Drew Reese May 29 '23 at 18:28
  • ok but how to use it i try to use `React.lazy` but i can't because it throws the error `Type '{ children: Element[]; }' is not assignable to type '() => Promise<{ default: ComponentType; }>'. Type '{ children: Element[]; }' provides no match for the signature '(): Promise<{ default: ComponentType; }>'.ts(2322) 'React.lazy' cannot be used as a JSX component. Its return type 'LazyExoticComponent>' is not a valid JSX element.ts(2786) ` and i can not solve – mahmoud2 nasser2 May 30 '23 at 11:31
  • Are you trying to lazy load *some* React component here, `User`? Are you trying to do some code splitting? React `Suspense`/`Lazy` has nothing at all to do with any data a component may be loading ***after*** the component has been loaded, e.g. mounted. Like I said, the code you have shared isn't lazily loading any components so there's nothing to show a loading indicator for. – Drew Reese May 30 '23 at 15:43

0 Answers0