当前正在学习如何将RTK与typescript一起使用。我有两个切片,一个是用RTK查询获取数据的切片(称为apiSlice.ts
),另一个是使用createSlice为我的todo应用程序处理同步状态更改的切片(也称为snackbarSlice.ts
)。
我在snackbarSlice中设置的初始状态根本没有保存到商店中,在chrome redux devtools和console.log中也进行了检查,但它们确实包含了与apiSlice相关的信息,只需注意与snackbar相关的信息。你知道我做错了什么吗?我觉得我开始做这件事已经太久了。
在控制台中,我得到一个错误:Uncaught TypeError:无法读取CustomSnackbar(CustomSnackbar.tsx:12:1)上未定义的(读取"isOpen")的属性,这在给定状态对象没有isOpen键的情况下是有意义的。
以下是我的代码:
snackbarSlice.ts
:
import { RootState } from "../store";
type SnackbarState = {
content: string;
isOpen: boolean;
};
const initialState: SnackbarState = {
content: "",
isOpen: false,
};
export const snackbarSlice = createSlice({
name: "snackbar",
initialState,
reducers: {
openSnackbar: (state, action: PayloadAction<string>) => {
state.isOpen = true;
state.content = action.payload;
},
closeSnackbar: (state) => {
state.isOpen = false;
state.content = "";
},
},
});
export const { openSnackbar, closeSnackbar } = snackbarSlice.actions;
export const selectIsSnackbarOpen = (state: RootState): boolean =>
state.snackbar.isOpen;
export const selectSnackbarContent = (state: RootState): string =>
state.snackbar.content;
export default snackbarSlice.reducer;
rootReducer.ts
import { apiSlice } from "./features/apiSlice";
import snackbarReducer from "./features/snackbarSlice";
const rootReducer = combineReducers({
snackbar: snackbarReducer,
[apiSlice.reducerPath]: apiSlice.reducer,
});
export default rootReducer;
存储.ts
import { apiSlice } from "./features/apiSlice";
import rootReducer from "./rootReducer";
export const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(apiSlice.middleware),
});
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
index.tsx
import { App } from "./components/app/App";
import React from "react";
import { ApiProvider } from "@reduxjs/toolkit/dist/query/react";
import { apiSlice } from "./store/features/apiSlice";
import { Provider } from "react-redux";
import { store } from "./store/store";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<Provider store={store}>
<ApiProvider api={apiSlice}>
<App />
</ApiProvider>
</Provider>
</React.StrictMode>
);
customSackbar.tsx
import { useAppDispatch, useAppSelector } from "../../hooks/reduxHooks";
import {
closeSnackbar,
selectIsSnackbarOpen,
selectSnackbarContent,
} from "../../store/features/snackbarSlice";
import styles from "./CustomSnackbar.module.css";
export const CustomSnackbar = (): ReactElement => {
const dispatch = useAppDispatch();
const isSnackbarOpen = useAppSelector(selectIsSnackbarOpen);
const snackbarContent = useAppSelector(selectSnackbarContent);
const handleClose = (): void => {
dispatch(closeSnackbar());
};
return (
<div>
{isSnackbarOpen && (
<div className={styles["snackbar"]}>
<div>
<span className={styles["snackbar-btn"]} onClick={handleClose}>
x
</span>
{snackbarContent}
</div>
</div>
)}
</div>
);
};
在任何需要打开小吃条的文件中,我都会运行以下代码:ispatch(openSnackbar("An error occurred while deleting task."));
有没有想过我会错过什么?
问题似乎是index.tsx
中的ApiProvider
。这是无关的和不必要的,因为apiSlice
在传递给Provider
时应该已经包含在存储中。
ApiProvider
如果您还没有Redux,则可以用作提供程序存储。
危险
将其与现有的Redux商店一起使用会导致相互冲突。如果您已经在使用Redux,请按照《入门》指南中的说明进行操作。
该应用程序使用的是最接近的Redux上下文/提供程序,即ApiProvider
,它不包括snackbar
状态/减少程序。
卸下ApiProvider
组件。
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);