2

Fairly basic boolean value set up in my redux store to know whether a sidebar is expanded or not. The problem I'm facing is that (although the default value is false), whenever I click the toggle button, false is outputted first. But if it is initially false then when it is clicked first it should be true.

I was having this problem with local state, so I switched to redux as I know state is async. Was hoping managing the value via reducers in the redux store would fix it.

// Fetch redux state
  const sidebar = useSelector(state => state.sidebar);
  const { isExpanded } = sidebar;
  
  const toggleSidebar = () => {
    dispatch({
      type: TOGGLE_SIDEBAR,
      payload: !isExpanded
    });
    console.log(isExpanded);
  }

The store and reducer is fairly self explanatory:

import { TOGGLE_SIDEBAR } from '../types/sidebar.types'

const initialState = {
    isExpanded: false
}

export const sidebarReducer = (state = initialState, action) => {
    switch(action.type) {
        case TOGGLE_SIDEBAR:
            return {
                isExpanded: action.payload
            }

        default:
            return state
    }
}

Store.js

const reducer = combineReducers({
    sidebar: sidebarReducer
});

const initialState = {

}

const middleware = [thunk];

const store = createStore(
    reducer,
    initialState,
    composeWithDevTools(applyMiddleware(...middleware))
);

export default store;
BranOIE
  • 400
  • 4
  • 19
  • Is the state never updating? Or is your `console.log()` just showing the old value? If the latter, this is *conceptually* a duplicate of [this](https://stackoverflow.com/q/54069253/328193). State updates are asynchronous and batched. You won't *immediately* see the change to the variable right after invoking the state update. – David Dec 19 '22 at 20:38
  • @David Yeah so basically it acts how it should only from the second click onwards. So you're saying the state IS changing, just not showing it has? – BranOIE Dec 19 '22 at 20:39
  • Whether or not the state is actually being updated is something you would need to confirm. Generally, if state is being referenced in a component, then presumably that component *uses* that state value in some way, such as displaying it or changing its display based on the value. Your debugging/testing should certainly include checking if the component does what you expect it to do. If that `console.log` statement is your only test and your only indication of a problem then this is basically just a misunderstanding in your expectations, as that particular line of code won't need a new value. – David Dec 19 '22 at 20:42
  • @David Yeah I put a turnery operator in one of my divs to append a class if the state is true and when I click the button I can see the class appear. Guess it's doing it's job. Redux dev tools is annoying to use, doesn't show live updates – BranOIE Dec 19 '22 at 20:48

1 Answers1

0

You are looking at old ("stale") data that will never get updated.

See this example:

let state = { sidebar: { isExpanded: false } }
const sidebar = state.sidebar
state = { sidebar: { isExpanded: true } }

state is now { sidebar: { isExpanded: true } }, but sidebar is still { isExpanded: false } - it is a separate variable that contains an object that was part of the former state, not the current state.

If practice, this is rarely a problem - if you don't immediately log it, but just use it in render that state change will trigger a rerender and within that rerender, you have a new sidebar variable that now points to the latest value.

phry
  • 35,762
  • 5
  • 67
  • 81