solve ReactDOM.render is no longer supported in React 18 but make useselector doesn't rerender

Viewed 245

I got this error in my app

Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot

here is the old version of code of index.ts:

let persistor = persistStore(store)

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate persistor={persistor}>
        <App />
      </PersistGate>
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
)

I solved this warning with the code below:

let persistor = persistStore(store)

//@ts-ignore
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
  <Provider store={store}>
    <PersistGate persistor={persistor}>
      <App />
    </PersistGate>
  </Provider>
</React.StrictMode>
)

but once I solved the problem above,a new problem appeared.The useselector hook did not rerender the component when the state in redux changed.below is the code I setup redux.

hook.ts

import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import { AppDisPatch, RootState } from "./store";

export const useAppDispatch = () => useDispatch<AppDisPatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

playslice.ts

import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { PlayMode, Song } from "../types/GlobalTypes";
import { RootState } from "./store";

export type PlayState = {
  // 播放状态
  playing: boolean;

  // 播放模式
  playMode: PlayMode;

  // 歌曲列表
  songList: Song[];

  // 播放列表
  playList: Song[];

  // 当前正在播放的索引
  currentIndex: number;
}

const defaultState: PlayState = {
  playing: false,
  songList: [],
  playList: [],
  playMode: { type: 'loop', label: '循环' },
  currentIndex: -1
}

export const playerSlice = createSlice({
  name: 'player',
  initialState: defaultState,
  reducers: {
    setPlaying: (state, action: PayloadAction<{ playing: boolean }>) => {
      return { ...state, playing: action.payload.playing }
    },
    setPlayList: (state, action: PayloadAction<{ playList: Song[] }>) => {
      return { ...state, playList: action.payload.playList }
    },
    setSongList: (state, action: PayloadAction<{ songList: Song[] }>) => {
      return { ...state, songList: action.payload.songList }
    },
    setPlayMode: (state, action: PayloadAction<{ playMode: PlayMode }>) => {
      return { ...state, playMode: action.payload.playMode }
    },
    setCurrentIndex: (state, action: PayloadAction<{ currentIndex: number }>) => {
      return { ...state, currentIndex: action.payload.currentIndex }
    },
  }
})

export const { setPlaying, setPlayList, setSongList, setPlayMode, setCurrentIndex } = playerSlice.actions

export const selectPlaying = (state: RootState) => state.playReducer.playing
export const selectPlayList = (state: RootState) => state.playReducer.playList
export const selectSongList = (state: RootState) => state.playReducer.songList
export const selectPlayMode = (state: RootState) => state.playReducer.playMode
export const selectCurrentIndex = (state: RootState) => state.playReducer.currentIndex


export default playerSlice.reducer

store.ts

import { combineReducers, configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
import persistReducer from 'redux-persist/es/persistReducer'
import storage from 'redux-persist/lib/storage';
import playReducer from './playerSlice'

const reducers = combineReducers({
  playReducer
})

const persistConfig = {
  key: 'root',
  storage
};

const persistedReducer = persistReducer(persistConfig, reducers)

const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) => getDefaultMiddleware({
    serializableCheck: false
  })
})

export type RootState = ReturnType<typeof store.getState>

export type AppDisPatch = typeof store.dispatch

export default store

homecomponent.ts

const playList = useAppSelector((state) => state.playReducer.playList)
  const songList = useAppSelector((state) => state.playReducer.songList)
  const currentIndex = useAppSelector((state) => state.playReducer.currentIndex)
  const dispatch = useAppDispatch()

the question is when the code of the index.ts is the old version,useselector will successfully set the state in redux and rerender home component,but the new version of index.ts will not.I don't know why this problem appears,and if I can solve the warning and make redux work.Thanks to anynoe who can help me.

1 Answers

I ran into the same issue. Upgrading to react-redux 8.0.2 fixed it for me.

The release notes for react-redux latest major release (https://github.com/reduxjs/react-redux/releases/tag/v8.0.0) start off with:

This major version release updates useSelector, connect, and for compatibility with React 18

Related