Я пытаюсь сопоставить состояние моего магазина с моими реквизитами с помощью mapStateToProps
. В частности, свойство isFetching
в состоянии authentication
моего магазина. Однако Typescript сообщает мне
Property 'isFetching' does not exist on type 'never'.
Не совсем уверен, что не так. Похоже на проблему типа, но я не уверен, в чем проблема.
interface IMapStateToProps {
isFetching: boolean;
}
const mapStateToProps = (
state: AppState,
): IMapStateToProps => ({
isFetching: state.authentication.isFetching,
});
Отображает ошибку: Property 'isFetching' does not exist on type 'never'.
Однако приведенный ниже код:
const mapStateToProps = (
state: AppState,
ownProps: AuthenticationPageProps
): IMapStateToProps => {
console.log(state.authentication);
return { isFetching: false };
};
Производит:
errors: []
isFetching: false
user: null
Магазин:
import { createStore, applyMiddleware, combineReducers } from "redux";
import thunk, { ThunkMiddleware } from "redux-thunk";
import { authenticationReducer } from "../reducers/authenticationReducer";
import { AppActions } from "../../types/AppActionTypes";
const initialState = {};
export const rootReducer = combineReducers({
authentication: authenticationReducer,
});
export type AppState = ReturnType<typeof rootReducer>;
const middlewares = [thunk as ThunkMiddleware<AppState, AppActions>];
const store = createStore(
rootReducer,
applyMiddleware(...middlewares)
);
export default store;
Типы:
import { Error } from "./Error";
import { User } from "./User";
export const LOGIN_REQUEST = "LOGIN_REQUEST";
export const LOGIN_SUCCESS = "LOGIN_SUCCESS";
export const LOGIN_FAILURE = "LOGIN_FAILURE";
export const LOGOUT_REQUEST = "LOGOUT_REQUEST";
export const LOGOUT_SUCCESS = "LOGOUT_SUCCESS";
export const LOGOUT_FAILURE = "LOGOUT_FAILURE";
export const REGISTER_REQUEST = "REGISTER_REQUEST";
export const REGISTER_SUCCESS = "REGISTER_SUCCESS";
export const REGISTER_FAILURE = "REGISTER_FAILURE";
export const CHECK_LOGGED_IN_REQUEST = "CHECK_LOGGED_IN_REQUEST";
export const CHECK_LOGGED_IN_FAILURE = "CHECK_LOGGED_IN_FAILURE";
export const CHECK_LOGGED_IN_SUCCESS = "CHECK_LOGGED_IN_SUCCESS";
export interface AuthenticationState {
isFetching: boolean;
user: User | null;
errors: Error[];
}
export interface LoginRequestAction {
type: typeof LOGIN_REQUEST;
isFetching: boolean;
}
export interface LoginSuccessAction {
type: typeof LOGIN_SUCCESS;
isFetching: boolean;
user: {
email: string;
};
}
export interface LoginFailureAction {
type: typeof LOGIN_FAILURE;
isFetching: boolean;
}
export interface LogoutRequestAction {
type: typeof LOGOUT_REQUEST;
isFetching: boolean;
}
export interface LogoutSuccessAction {
type: typeof LOGOUT_SUCCESS;
isFetching: boolean;
}
export interface LogoutFailureAction {
type: typeof LOGOUT_FAILURE;
isFetching: boolean;
}
export interface RegisterRequestAction {
type: typeof REGISTER_REQUEST;
isFetching: boolean;
}
export interface RegisterSuccessAction {
type: typeof REGISTER_SUCCESS;
isFetching: boolean;
}
export interface RegisterFailureAction {
type: typeof REGISTER_FAILURE;
isFetching: boolean;
}
export interface CheckLoggedInRequestAction {
type: typeof CHECK_LOGGED_IN_REQUEST;
isFetching: boolean;
}
export interface CheckLoggedInSuccesstAction {
type: typeof CHECK_LOGGED_IN_SUCCESS;
isFetching: boolean;
}
export interface CheckLoggedInFailureAction {
type: typeof CHECK_LOGGED_IN_FAILURE;
isFetching: boolean;
}
export type AuthenticationActionTypes =
| RegisterFailureAction
| RegisterSuccessAction
| RegisterRequestAction
| LoginFailureAction
| LoginRequestAction
| LoginSuccessAction
| LogoutFailureAction
| LogoutRequestAction
| LogoutSuccessAction
| CheckLoggedInFailureAction
| CheckLoggedInRequestAction
| CheckLoggedInSuccesstAction;
Редуктор:
import {
LOGOUT_SUCCESS,
LOGOUT_REQUEST,
LOGOUT_FAILURE,
LOGIN_FAILURE,
LOGIN_SUCCESS,
LOGIN_REQUEST,
REGISTER_FAILURE,
REGISTER_SUCCESS,
REGISTER_REQUEST,
AuthenticationState,
AuthenticationActionTypes,
CHECK_LOGGED_IN_REQUEST,
CHECK_LOGGED_IN_SUCCESS,
CHECK_LOGGED_IN_FAILURE,
} from "../../types/Authentication";
export const AuthenticationReducerDefaultState = {
errors: [],
isFetching: false,
user: null,
};
export const authenticationReducer = (
state = AuthenticationReducerDefaultState,
action: AuthenticationActionTypes
): AuthenticationState => {
switch (action.type) {
case LOGIN_REQUEST:
case LOGOUT_REQUEST:
case REGISTER_REQUEST:
case CHECK_LOGGED_IN_REQUEST:
return {
...state,
isFetching: true,
};
case LOGIN_SUCCESS:
return {
...state,
isFetching: false,
user: {
email: action.user.email,
},
};
case LOGOUT_SUCCESS:
return { ...state, isFetching: false };
case CHECK_LOGGED_IN_SUCCESS:
return { ...state, isFetching: false };
case REGISTER_SUCCESS:
return { ...state, isFetching: false };
case LOGIN_FAILURE:
return { ...state, isFetching: false };
case LOGOUT_FAILURE:
return { ...state, isFetching: false };
case REGISTER_FAILURE:
return { ...state, isFetching: false };
case CHECK_LOGGED_IN_FAILURE:
return { ...state, isFetching: false };
default:
return state;
}
};
компонент:
interface AuthenticationPageProps {
location: { state: string };
}
interface AuthenticationPageState {
email: string;
password: string;
passwordConfirmation: string;
errors: string;
}
type Props = AuthenticationPageProps & IMapDispatchToProps & IMapStateToProps;
const AuthenticationPage = (props: Props) => {
const [lostPasswordState, setLostPasswordState] = useState("");
const [registerState, setRegisterState] = useState({
email: "",
password: "",
passwordConfirmation: "",
});
const [loginState, setLoginState] = useState({
email: "",
password: "",
});
const handleLostPasswordSubmit = (event: SyntheticEvent) => {
console.log("Lost Password Form submitted");
event.preventDefault();
};
const handleLoginSubmit = (event: SyntheticEvent) => {
console.log("Login Form submitted");
event.preventDefault();
props.login(loginState.email, loginState.password);
};
const handleRegistrationSubmit = (event: SyntheticEvent) => {
console.log("Registration Form submitted");
event.preventDefault();
props.register(
registerState.email,
registerState.password,
registerState.passwordConfirmation
);
};
const handleLoginOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setLoginState({
...loginState,
[event.target.name]: event.target.value,
});
};
const handleLostPasswordOnChange = (
event: React.ChangeEvent<HTMLInputElement>
) => {};
const handleRegisterOnChange = (
event: React.ChangeEvent<HTMLInputElement>
) => {
setRegisterState({
...registerState,
[event.target.name]: event.target.value,
});
};
return (
<React.Fragment>
login
<LoginForm onSubmit={handleLoginSubmit} onChange={handleLoginOnChange} />
register
<RegistrationForm
onSubmit={handleRegistrationSubmit}
onChange={handleRegisterOnChange}
/>
lost password
<LostPasswordForm
onSubmit={handleLostPasswordSubmit}
onChange={handleLostPasswordOnChange}
/>
</React.Fragment>
);
};
interface IMapStateToProps {
isFetching: boolean;
}
interface IMapDispatchToProps {
login: (email: string, password: string) => void;
register: (
email: string,
password: string,
passwordConfirmation: string
) => void;
}
const mapStateToProps = (
state: AppState,
ownProps: AuthenticationPageProps
): IMapStateToProps => {
console.log(state.authentication);
return { isFetching: false };
};
const mapDispatchToProps = (
dispatch: ThunkDispatch<any, any, AuthenticationActionTypes>,
ownProps: AuthenticationPageProps
): IMapDispatchToProps => ({
login: bindActionCreators(login, dispatch),
register: bindActionCreators(register, dispatch),
});
export default connect(mapStateToProps, mapDispatchToProps)(AuthenticationPage);