【发布时间】:2021-08-18 03:56:58
【问题描述】:
我正在使用 MongoDB、Express、React、Node (MERN) 项目。我在更改 redux 文件以实现 Material UI/core
我尝试通过 useSelector 以不同的方式访问数据,即使是使用 shallowEqual 方法。我也尝试在 DashBoardAdmin 中调用 getStudents()。同时也尝试使用 useEffect 来调度 (getStudents()) 与依赖数组。到目前为止,一切都没有奏效。然后尝试在 chrome 的检查部分进行调试,我发现在第一次重新加载页面时,恰好在 action.payload 上从后端获取数据,但它无法整体填充到状态中。这可能是 useSelector 获取空数组并提供“无法读取未定义的属性 'map'
的原因我认为,在引入 state 中的对象之后,reducers 的students.js 文件出现了问题。我正在尽力调试。
我的 index.js 文件:
import React from "react";
import ReactDOM from "react-dom";
import "./Styles/index.css";
import App from "./App";
import { Provider } from "react-redux";
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import { reducers } from "./redux/reducers/index";
const composeEnhancers =
typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
: compose;
const enhancer = composeEnhancers(compose(applyMiddleware(thunk)));
const store = createStore(reducers, enhancer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
我的 app.js 文件:
import React, { useEffect, useState } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import "./Styles/App.css";
import AdminSignIn from "./Pages/AdminSignIn";
import DashBoardAdmin from "./Pages/Admin";
import NavbarAdmin from "./Navbars/NavbarAdmin";
import BottomNavbar from "./Navbars/bottomNavbar";
import { useDispatch } from "react-redux";
import { Typography } from "@material-ui/core";
import { NotFound } from "./Not_Found/NotFound";
import { getStudents } from "./redux/actions/studentAction";
function App() {
const user = JSON.parse(localStorage.getItem("account"));
const dispatch = useDispatch();
useEffect(() => {
dispatch(getStudents());
}, [dispatch]);
return (
<>
<Router>
{user?.result?._id ? (
<NavbarAdmin />
) : (
<Typography variant="h2">{"Fetch"} Organization Name</Typography>)}
<Switch>
<Route path="/" exact>
<AdminSignIn />
</Route>
<Route path="/dashboard" exact>
<DashBoardAdmin />
</Route>
<Route >
<NotFound />
</Route>
</Switch>
<BottomNavbar />
</Router>
</>
);
}
export default App;
我的 DashBoardAdmin.js 文件:
import { Box, Button, Card, CardHeader, Chip, CircularProgress, Divider, Table, TableBody, TableCell, TableHead, TableRow, TableSortLabel, Tooltip} from "@material-ui/core";
import { Link } from 'react-router-dom'
import ArrowRightIcon from "@material-ui/icons/ArrowRight";
import moment from "moment";
import PerfectScrollbar from "react-perfect-scrollbar";
import { useSelector } from "react-redux";
const DashBoardAdmin = () => {
const { students, isLoading } = useSelector((state) => state.students);
return (
<div className="padding-grid">
<Card>
<CardHeader title="Latest updates on students" />
<Divider />
<PerfectScrollbar>
<Box sx={{ minWidth: 800 }}>
<Table>
<TableHead>
<TableRow>
<TableCell>Roll Number</TableCell>
<TableCell>Name of student</TableCell>
<TableCell sortDirection="desc">
<Tooltip enterDelay={300} title="Sort">
<TableSortLabel active direction="desc">
Date of Admission
</TableSortLabel>
</Tooltip>
</TableCell>
<TableCell>Status</TableCell>
</TableRow>
</TableHead>
{isLoading ? (
<CircularProgress />
) : (
<TableBody>
{students.map((stu) => (
<TableRow hover key={stu.id}>
<TableCell>{stu.rollNumber}</TableCell>
<TableCell>{stu.firstName} {" "} {stu.lastName} + {" "} {stu.surname}</TableCell>
<TableCell>
{moment(stu.createdAt).format("DD/MM/YYYY")}
</TableCell>
<TableCell>
<Chip color="primary" label={stu.status} size="small" />
</TableCell>
</TableRow>
))}
</TableBody>
)}
</Table>
</Box>
</PerfectScrollbar>
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
p: 2,
}}>
<Link to="/students-info">
<Button
color="primary"
endIcon={<ArrowRightIcon />}
size="small"
variant="text">
View all
</Button>
</Link>
</Box>
</Card>
</div>
);
};
export default DashBoardAdmin;
我的 redux studentAction.js 文件:
import { FETCH_STUDENTS, START_LOADING, END_LOADING } from "../constants/actionTypes";
import * as api from "../api/index.js";
export const getStudents = () => async (dispatch) => {
try {
dispatch({ type: START_LOADING })
const { data } = await api.fetchStudents();
dispatch({ type: FETCH_STUDENTS, payload: data });
dispatch({ type: END_LOADING})
} catch (error) {
console.log(error);
}
};
我的 API index.js 文件:
import axios from "axios";
const API = axios.create({ baseURL: "http://localhost:5000" });
API.interceptors.request.use((req) => {
if (localStorage.getItem("account")) {
req.headers.Authorization = `Bearer ${
JSON.parse(localStorage.getItem("account")).token
}`;
}
return req;
});
export const fetchStudents = () => API.get("/students-info");
students.js 的减速器,最好的猜测是这里出了点问题,或者它是在我包含 isLoading 之后开始的:
import { FETCH_STUDENTS, START_LOADING, END_LOADING } from "../constants/actionTypes";
function students(state = { isLoading: true, students: [] }, action) {
switch (action.type) {
case START_LOADING:
return { ...state, isLoading: true };
case END_LOADING:
return { ...state, isLoading: false };
case FETCH_STUDENTS:
return { ...state, students: action.payload.data };
default:
return state;
}
}
export default students;
index.js 合并reducer文件:
import { combineReducers } from "redux";
import students from "./students";
import auth from "./auth";
export const reducers = combineReducers({ students, auth });
我得到的错误是:
Uncaught TypeError: Cannot read property 'map' of undefined
at DashBoardAdmin (DashBoardAdmin.js:51)
at renderWithHooks (react-dom.development.js:14985)
at updateFunctionComponent (react-dom.development.js:17356)
at beginWork (react-dom.development.js:19063)
at HTMLUnknownElement.callCallback (react-dom.development.js:3945)
at Object.invokeGuardedCallbackDev (react-dom.development.js:3994)
at invokeGuardedCallback (react-dom.development.js:4056)
at beginWork$1 (react-dom.development.js:23964)
at performUnitOfWork (react-dom.development.js:22776)
at workLoopSync (react-dom.development.js:22707)
at renderRootSync (react-dom.development.js:22670)
at performSyncWorkOnRoot (react-dom.development.js:22293)
at react-dom.development.js:11327
at unstable_runWithPriority (scheduler.development.js:468)
at runWithPriority$1 (react-dom.development.js:11276)
at flushSyncCallbackQueueImpl (react-dom.development.js:11322)
at flushSyncCallbackQueue (react-dom.development.js:11309)
at batchedUpdates$1 (react-dom.development.js:22387)
at Object.notify (Subscription.js:19)
at Subscription.notifyNestedSubs (Subscription.js:90)
at Subscription.handleChangeWrapper (Subscription.js:95)
at Object.dispatch (redux.js:297)
at dispatch (<anonymous>:3856:17)
at index.js:11
at dispatch (redux.js:659)
at studentAction.js:35
还有一个错误:
Warning: validateDOMNesting(...): <div> cannot appear as a child of <table>.
at div
at CircularProgress (http://localhost:4000/static/js/vendors~main.chunk.js:80761:23)
at WithStyles (http://localhost:4000/static/js/vendors~main.chunk.js:119309:31)
at table
at Table (http://localhost:4000/static/js/vendors~main.chunk.js:102171:23)
at WithStyles (http://localhost:4000/static/js/vendors~main.chunk.js:119309:31)
at div
at StyledComponent (http://localhost:4000/static/js/vendors~main.chunk.js:119080:28)
at div
at ScrollBar (http://localhost:4000/static/js/vendors~main.chunk.js:231982:5)
at div
at Paper (http://localhost:4000/static/js/vendors~main.chunk.js:94231:23)
我通过在 students.js 文件中使用简单的 redux 语法从后端获取数据:
import { FETCH_STUDENTS } from "../constants/actionTypes";
export default (students = [], action) => {
switch (action.type) {
case FETCH_STUDENTS:
return action.payload;
default:
return students;
}
};
需要另一种方法来实现 isLoading 或 START_LOADING / END_LOADING 向 UI 分派
【问题讨论】:
-
快速修复:如果
students是undefined{(students || []).map((stu) => (,则使用空数组 -
@LindaPaiste 是的,这个方法可以帮助我至少看到 UI 部分,错误停止在屏幕上弹出,但数据仍然没有更新到 redux 存储中。感谢上述方法。如果您能解决用数据填充状态的任何问题,我们将不胜感激。
-
我怀疑reducer中的“students: action.payload.data”应该是“students: action.payload”。但这取决于您的 API 响应的格式。
-
@LindaPaiste 是的尝试过,但仍然返回空数组。但是我通过实现 export default (students = [], action) => { switch (action.type) { case FETCH_STUDENTS: return action.payload; 来获取数据。默认:返回学生; } };但同样,无法实现 START_LOADING 和 END_LOADING。任何建议或者添加 START_LOADING
标签: javascript reactjs redux react-redux react-router-dom