Gotey
Gotey

Reputation: 629

State not updating with assigned constant with useSelector in react-redux

I have within my functional component:

   const selectedHotel = useSelector(state => state.selectedHotel)
          const dispatch = useDispatch()
    

const handleHotelSelectChange = (event) =>{
  console.log("DISPatching...", selectedHotel, event.target.childNodes[event.target.selectedIndex].id)
  dispatch(changeSelectedHotel(event.target.childNodes[event.target.selectedIndex].id))  
}

const handleAutoHotelSelect = (event) => {
 console.log("DISPatching...", selectedHotel, event, event)
 dispatch(changeSelectedHotel(event))  
}

And the reducer looks like this:


export const configHotelReducer = function (state = "all" , action) {
  console.log("REDUCER", state, action)
    switch (action.type) {
      case "SELECT_HOTEL":
        return action.payload;
      default:
        return state;
    }
  };

in

  console.log("DISPatching...", selectedHotel, event.target.childNodes[event.target.selectedIndex].id)

I can see selectedHotel is always undefined, but in:

  console.log("REDUCER", state, action)

I can see how it updates with every dispatch, how can I do for selectedHotel to return the updated state?


this is how my action looks like:

import {SELECT_HOTEL} from './constants'

export const changeSelectedHotel = (id) => {
    console.log({type: SELECT_HOTEL,  payload: id, })
    
    return ({
    type: SELECT_HOTEL,
    payload: id,
}) }

Upvotes: 1

Views: 340

Answers (1)

HMR
HMR

Reputation: 39250

Here is an example of how you can do it and how to add redux devtools to your code:

const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;

const initialState = {
  hotels: [
    { id: 1, name: 'Hotel One' },
    { id: 2, name: 'Hotel Two' },
    { id: 3, name: 'Hotel Three' },
  ],
  selectedHotel: undefined,
};
//action types
const SELECT_HOTEL_1 = 'SELECT_HOTEL_1';
const SELECT_HOTEL_2 = 'SELECT_HOTEL_2';
//action creators
const setHotel1 = (hotel) => ({
  type: SELECT_HOTEL_1,
  payload: hotel,
});
const setHotel2 = (hotelId) => ({
  type: SELECT_HOTEL_2,
  payload: hotelId,
});
const reducer = (state, { type, payload }) => {
  if (type === SELECT_HOTEL_1) {
    return {
      ...state,
      selectedHotel: payload,
    };
  }
  //other way of selecting hotel, logic is in reducer
  //  this would be the better way but you need hotels
  //  in state
  if (type === SELECT_HOTEL_2) {
    return {
      ...state,
      selectedHotel: state.hotels.find(
        ({ id }) => id === payload
      ),
    };
  }
  return state;
};
//selectors
const selectHotels = (state) => state.hotels;
const selectSelectedHotel = (state) => state.selectedHotel;
//simple thunk implementation
const thunk = ({ dispatch, getState }) => (next) => (
  action
) =>
  typeof action === 'function'
    ? action(dispatch, getState)
    : next(action);
//creating store with redux dev tools
const composeEnhancers =
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  reducer,
  initialState,
  composeEnhancers(applyMiddleware(thunk))
);
const App = () => {
  const hotels = useSelector(selectHotels);
  const hotel = useSelector(selectSelectedHotel);
  const dispatch = useDispatch();
  const change = React.useCallback(
    (e) =>
      dispatch(
        setHotel1(
          hotels.find(
            ({ id }) => id === Number(e.target.value)
          )
        )
      ),
    [dispatch, hotels]
  );
  return (
    <div>
      <label>
        select hotel 1
        <select
          // cannot use hotel?.id because SO babel is too old
          value={hotel && hotel.id}
          onChange={change}
        >
          <option>Select a hotel</option>
          {hotels.map((hotel) => (
            <option key={hotel.id} value={hotel.id}>
              {hotel.name}
            </option>
          ))}
        </select>
      </label>
      <label>
        select hotel 2
        <select
          // cannot use hotel?.id because SO babel is too old
          value={hotel && hotel.id}
          onChange={(e) =>
            dispatch(setHotel2(Number(e.target.value)))
          }
        >
          <option>Select a hotel</option>
          {hotels.map((hotel) => (
            <option key={hotel.id} value={hotel.id}>
              {hotel.name}
            </option>
          ))}
        </select>
      </label>
    </div>
  );
};

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
<div id="root"></div>

Upvotes: 1

Related Questions