在 react-redux 中使用 useSelector 未使用分配的常量更新状态

时间:2021-02-25 12:28:58

标签: reactjs redux react-redux

我的功能组件中有:

   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))  
}

减速器看起来像这样:


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

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

我可以看到 selectedHotel 始终未定义,但在:

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

我可以看到它如何随着每次调度而更新,我该如何让 selectedHotel 返回更新后的状态?


这是我的动作的样子:

import {SELECT_HOTEL} from './constants'

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

1 个答案:

答案 0 :(得分:1)

以下是一个示例,说明如何执行此操作以及如何将 redux devtools 添加到您的代码中:

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>