reactjsreact-reduxredux-toolkitreact-suspense

Why doesn't react suspense work properly with redux toolkit query?


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>,
)

Solution

  • Currently, RTK Query does not have built-in support for Suspense. If you're interested in using Suspense with RTK Query, you can subscribe to this issue on GitHub to stay updated on any developments or changes related to adding Suspense support to RTK Query. Hope this helps!