Coder Social home page Coder Social logo

Comments (10)

EskiMojo14 avatar EskiMojo14 commented on May 29, 2024 6

A more detailed explanation of the change for context:

Prior to Redux v5, the handling for preloadedState was a little hacky. There was only the one State type parameter for reducers, and it was assumed that in most cases preloadedState would just be this State type. However, the most common exception to this was the reducer created by combineReducers, which would accept Partial<State>.

For a long time this was handled by a special $CombinedState brand, which would tell createStore (and configureStore) that it was allowed to have a partial preloadedState instead. This was unintuitive, and had some user-reported issues.

In v5, we took the opportunity to rethink how preloadedState was handled. In practicality, preloadedState is anything that's valid to pass as the first parameter to your reducer, as long as the reducer still returns its normal State. Following this logic, we added an optional third PreloadedState type parameter to the Reducer type (which defaults to State), which appears in the first parameter of the reducer but not the return type.

type Reducer<S, A extends Action = Action, P = S> = (state: S | P | undefined, action: A) => S

This means that the result of combineReducers is now Reducer<State, Action, Partial<State>>.

However when you pass it to persistReducer, it doesn't know to preserve the PreloadedState type parameter, so you end up with Reducer<State, Action> - and suddenly preloadedState is no longer allowed to be partial.

Users can fix this themselves by adding an overload that knows to preserve PreloadedState:

import type { Action, Reducer } from "redux";
import type { PersistConfig, PersistState } from "redux-persist";

declare module "redux-persist" {
  export function persistReducer<S, A extends Action = Action, P = S>(
    config: PersistConfig<S>,
    baseReducer: Reducer<S, A, P>,
  ): Reducer<
    S & { _persist: PersistState },
    A,
    P & { _persist?: PersistState }
  >;
}

But it'd obviously be nicer if the library could be updated to handle this itself 🙂

from redux-persist.

zvs001 avatar zvs001 commented on May 29, 2024 2

Update is pretty important. I experience issue that useSelector doesn't make component to rerender on state change.
Issue gone when I downgrade to RTK v1 or drop redux-persist.

from redux-persist.

Haschtl avatar Haschtl commented on May 29, 2024

I also updated to RTK v2 and I'm not having any type-issues. Where did you encounter type errors?

from redux-persist.

xsjcTony avatar xsjcTony commented on May 29, 2024

reduxjs/redux-toolkit#3946 (comment)

from redux-persist.

phryneas avatar phryneas commented on May 29, 2024

You probably will also have to override the dependency. You can do so with npm overrides:

in your package.json:

{
  // ...
  "dependencies": {
    "@reduxjs/toolkit": "^2.0.1",
    "react-redux": "^9.0.2",
    "redux-persist": "^6.0.0"
  },
  "overrides": {
    "redux-persist": {
      "redux": "^5.0.0"
    }
  }
}

from redux-persist.

xsjcTony avatar xsjcTony commented on May 29, 2024

I guess ">4.0.0" is including v5, at least I didn't encounter any issue when installing dependencies

from redux-persist.

phryneas avatar phryneas commented on May 29, 2024

@xsjcTony Good point. One of our users had problems with that, but I didn't notice it was using >.

from redux-persist.

lucipacurar avatar lucipacurar commented on May 29, 2024

Same issue here: useSelector doesn't trigger rerender and my app is stuck in a weird state.

from redux-persist.

EskiMojo14 avatar EskiMojo14 commented on May 29, 2024

could either of you put together a reproduction of the issue?

from redux-persist.

zvs001 avatar zvs001 commented on May 29, 2024

Here is store setup example that I have in app.
I don't remember versions. I think @reduxjs/toolkit was 2.0.1 or 2.1.0

Also react-redux to reproduce requires v9+. I downgraded to v8 to fix the issue

store.tsx
import AsyncStorage from '@react-native-async-storage/async-storage'
import { configureStore, ThunkAction } from '@reduxjs/toolkit'
import { shallowEqual, TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import { persistStore, persistReducer, FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER } from 'redux-persist'
import { Action } from './app/actions'
import { middleware } from './middleware'
import AppReducers from './index'

const persistedReducer = persistReducer(
  {
    key: 'root',
    storage: AsyncStorage,
    version: 2,
  },
  AppReducers,
)

export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) => {
    return getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }).concat(middleware)
  },
})

// const sagaMiddleware = createSagaMiddleware()
export const persistor = persistStore(store)

// sagaMiddleware.run(saga)

export default {
  store,
  persistor,
}

export const useAppDispatch = () => useDispatch<ReduxDispatch>()
export const useAppSelector: TypedUseSelectorHook<ReduxState> = (selector) => useSelector(selector, shallowEqual)

/* Types */
export type ReduxStore = typeof store
export type ReduxState = ReturnType<typeof AppReducers>
export type ReduxDispatch = typeof store.dispatch
export type ReduxThunkAction<ReturnType = void> = ThunkAction<ReturnType, ReduxState, unknown, Action>
slice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit'

interface State {
  deviceLocale: string
  appLocale: string
}

const initialState: State = {
  deviceLocale: '',
  appLocale: '',
}

const slice = createSlice({
  name: 'SYSTEM',
  initialState,
  reducers: {
    setLocale(state, action: PayloadAction<Pick<State, 'appLocale' | 'deviceLocale'>>) {
      const { appLocale, deviceLocale } = action.payload
      state.appLocale = appLocale
      state.deviceLocale = deviceLocale
    },
  },
})

export const { reducer, actions } = slice
export default reducer

from redux-persist.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.