在我的功能组件中有:
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,
}) }
下面是如何做到这一点以及如何在代码中添加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>