#reactjs #typescript #object #redux #react-hooks
#reactjs #typescript #объект #сокращение #реагирующие хуки
Вопрос:
Я создал простое приложение Redux со следующими частями
import { useDispatch, useSelector } from "react-redux";
import { buyCakes } from "../redux/cake/cake.actions";
import { ICakeState } from "../redux/cake/cake.reducer";
import { changeEventType, formEventType } from "../models/events.model";
const CakeContainer: React.FC = () => {
const [buyCakeAmount, setBuyCakeAmount] = useState(1);
const numberOfCakes = useSelector<ICakeState, ICakeState["numberOfCakes"]>(
(state) => {
console.log(state);
return state.numberOfCakes;
}
);
const dispatch = useDispatch();
const changeHandler = (event: changeEventType) => {
setBuyCakeAmount(parseInt(event.target.value));
};
const submitHandler = (event: formEventType) => {
event.preventDefault();
dispatch(buyCakes(buyCakeAmount));
setBuyCakeAmount(1);
};
return (
<>
<h2>Number of cakes left in the shop: {numberOfCakes}</h2>
<form onSubmit={submitHandler}>
<input type="number" value={buyCakeAmount} onChange={changeHandler} />
<button type="submit">Buy Cakes</button>
</form>
</>
);
};
export default CakeContainer;
Редуктор
import { BUY_CAKE, BUY_CAKES } from "./cake.types";
import { CakeActionTypes } from "./cake.types";
export interface ICakeState {
numberOfCakes: number;
}
const INITIAL_STATE: ICakeState = {
numberOfCakes: 10,
};
const cakeReducer = (
state: ICakeState = INITIAL_STATE,
action: CakeActionTypes
) => {
switch (action.type) {
case BUY_CAKE:
return {
...state,
numberOfCakes: state.numberOfCakes - 1,
};
case BUY_CAKES:
return {
...state,
numberOfCakes: state.numberOfCakes - action.payload,
};
default:
return state;
}
};
export default cakeReducer;
Действия
import { BUY_CAKE, BUY_CAKES } from "./cake.types";
import { CakeActionTypes } from "./cake.types";
import { numberOfCakes } from "../../models/cake.model";
export const buyCake = (): CakeActionTypes => ({
type: BUY_CAKE,
});
export const buyCakes = (numberOfCakes: numberOfCakes): CakeActionTypes => ({
type: BUY_CAKES,
payload: numberOfCakes,
});
Типы
import { numberOfCakes } from "../../models/cake.model";
export const BUY_CAKE = "BUY_CAKE";
export const BUY_CAKES = "BUY_CAKES";
interface BuyCakeAction {
type: typeof BUY_CAKE;
}
interface BuyCakesAction {
type: typeof BUY_CAKES;
payload: numberOfCakes;
}
export type CakeActionTypes = BuyCakeAction | BuyCakesAction;
Магазин
import { combineReducers, createStore } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import cakeReducer from "./cake/cake.reducer";
export default createStore(
combineReducers([cakeReducer]),
composeWithDevTools()
);
Журнал в useSelector регистрирует этот объект
{"0":{"numberOfCakes":10}}
Разве он не должен просто возвращать состояние, не помещая его в объект с ключом ‘0’?
Кроме того, если я просто верну состояние следующим образом
state['0'].numberOfCakes
Я получаю сообщение об ошибке машинописного текста
Может кто-нибудь, пожалуйста, объяснить мне, почему это происходит и как это исправить, спасибо.
Ответ №1:
Первая проблема: useSelector
собирается вернуть вам ваше корневое состояние, поэтому вы передаете неправильные типы в свой общий здесь:
const numberOfCakes = useSelector<ICakeState, ICakeState["numberOfCakes"]>(
(state) => {
console.log(state);
return state.numberOfCakes;
}
);
Вторая проблема заключается в том, что combineReducers
принимает объект с различными редукторами, включая их имена, а не массив, поэтому вам нужно изменить его на:
export default createStore(
combineReducers({cakeReducer}),
composeWithDevTools()
);
export type RootState = ReturnType<typeof rootReducer>
а затем измените:
const numberOfCakes = useSelector<RootState>(
(state) => {
console.log(state);
return state.cakeReducer.numberOfCakes;
}
);