reduxreact-reduxredux-toolkitredux-reducers

React-redux Toolkit: Cannot set new state, when passing reducer as prop to another function


I am trying to use react redux toolkit and pass setter function to set new state on firebase's 'onAuthStateChanged'. The plan was to pass user's state (object or null) to reducer, depending if user is logged in or logged out. This is my first usage of redux, so I can't get why my code doesn't work. There is no errors, but in redux devtools state is always equal to null.

Configure Store:

import { configureStore } from '@reduxjs/toolkit'
import { Provider } from 'react-redux';
import userReducer from './utils/userReducer';

const store = configureStore({
  reducer: {
    user: userReducer,
  }
})

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

My reducer:

import { createSlice } from "@reduxjs/toolkit";

export const userSlice = createSlice({
    name: 'user',
    initialState: null,
    reducers: {
        setUser: (state, action) => {
            state = action.payload;
        }
    }
})

export const {setUser} = userSlice.actions;
export default userSlice.reducer;

Where I am dispatching it:

  import { setUser } from '../utils/userReducer'
  import { useDispatch } from 'react-redux'

  const dispatch = useDispatch()

  const handleLogin = async (e) => {
    e.preventDefault()
    const { user } = await logInWithEmail(email, password)
    await setCurrentUser(() => dispatch(setUser))
  }

Firebase function, where I am trying to use reducer:

export const setCurrentUser = async (setUser) => {
    await onAuthStateChanged(auth, (currentUser) => {
        setUser(currentUser)
    })
}

I understand, that with useContext it would be much easier, but I am trying to learn redux by implying it.


Solution

  • Try like that:

    import { setUser } from '../utils/userReducer'
    import { useDispatch } from 'react-redux'
    
    const dispatch = useDispatch()
    
    const handleLogin = async (e) => {
      e.preventDefault()
      const { user } = await logInWithEmail(email, password)
      // This line updated
      await setCurrentUser((currentUser) => dispatch(setUser(currentUser)))
    }
    

    The reason:

    your setCurrentUser function prop setUser is just function () => dispatch(setUser), but this function does not receive any prop, and dispatch(setUser) does not do anything. you need to pass value (payload) to reducer function.

    Additionally, try passing dispatch itself as prop and dispatch inside of onAuthStateChanged.

    export const setCurrentUser = async (dispatch) => {
      await onAuthStateChanged(auth, (currentUser) => {
        dispatch(setUser(currentUser))
      })
    }
    

    import setUser reducer function if handleLogin and setCurrentUser function is in different files separately.