Reputation: 367
I am working with MongoDB, Express, React, Node (MERN) project. I having the issue of "Cannot read property 'map' of undefined after changing the redux files to achieve loading effect from Material UI/core <CircularProgress />
I have tried to access data by useSelector in different ways, even with shallowEqual method. I tried to call the getStudents() inside DashBoardAdmin also. While also tried with useEffect to dispatch (getStudents()) with dependencies array. All didn't worked so far. Then tried to debug on inspect section of chrome, where I found that on first reload of page, there happens to get data from backend on action.payload but it isn't able to populate into the state as whole. That's might be reason that useSelector is getting an empty array & providing "Cannot read property 'map' of undefined
I assume, something went wrong after the students.js file of reducers, after introducing an object in the state. I am trying my best to debug.
My index.js file :
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")
);
My app.js file:
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;
My DashBoardAdmin.js file:
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;
My redux studentAction.js file:
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);
}
};
My API index.js file:
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");
My reducers by students.js and best guess is that something is wrong here or it started after I included 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 combine reducer file:
import { combineReducers } from "redux";
import students from "./students";
import auth from "./auth";
export const reducers = combineReducers({ students, auth });
Errors which I am getting are:
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
and another error:
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)
I am getting data from backend by using simple syntax of redux in the students.js file :
import { FETCH_STUDENTS } from "../constants/actionTypes";
export default (students = [], action) => {
switch (action.type) {
case FETCH_STUDENTS:
return action.payload;
default:
return students;
}
};
Need to get an alternative method of implementing isLoading or START_LOADING / END_LOADING dispatch to the UI
Upvotes: 1
Views: 216
Reputation: 506
ok after seeing your app.js I see you are using thunk and I think you have to use functions rather than passing objects directly.
Also I added an action to get the error just in case
import {
FETCH_STUDENTS,
START_LOADING,
END_LOADING,
} from "../constants/actionTypes";
import * as api from "../api";
const startLoading = () => {
return {
type: START_LOADING,
};
};
const fetchStudents = (data) => {
return {
type: FETCH_STUDENTS,
data,
};
};
const endLoading = (error) => {
return {
type: END_LOADING,
error,
};
};
export const getStudents = () => {
return async (dispatch) => {
dispatch(startLoading());
try {
const { data } = await api.fetchStudents()
dispatch(fetchStudents(data))
} catch (error) {
dispatch(endLoading(error.message));
}
};
};
import {
FETCH_STUDENTS,
START_LOADING,
END_LOADING,
} from "../../constants/actionTypes";
const initialState = {
isLoading: false,
error: "",
students: [],
};
function students(state = initialState, action) {
switch (action.type) {
case START_LOADING:
return { ...state, isLoading: true };
case END_LOADING:
return { ...state, isLoading: false, students: [], error: action.error };
case FETCH_STUDENTS:
return {
...state,
isLoading: false,
students: action.data,
};
default:
return state;
}
}
export default students;
your app.js and index.js is correct for me
and in your Admin.js you can use this condition
import { useSelector } from "react-redux";
const DashBoardAdmin = () => {
const { students, isLoading, error } = useSelector((state) => state.students);
return (
<>
{error === "" && (
<div className="padding-grid">
...
{isLoading || !students.length > 0 ? (
<h1>loading...</h1>
) : (
<div>
{students.map((stu) => (
<p key={stu.id}>{JSON.stringify(stu)}</p>
))}
</div>
)}
...
</div>
)}
</>
);
};
export default DashBoardAdmin;
Upvotes: 1