I need to render component by route "courses/:courseId"
, but I got an error "Uncaught TypeError: Cannot read properties of undefined". It's because courses
is empty just after render.
import React, { useEffect, useState } from 'react';
import { useParams, Link, useNavigate } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import { pipeDuration } from '../../helpers/pipeDuration';
import { transformDate } from '../../helpers/dateGenerator';
import { selectCourses, selectAuthors } from './selectors';
import { BACK_TO_COURSES } from '../../constants';
import classes from './CourseInfo.module.css';
import { getCourses } from '../../store/courses/thunk';
import { getAuthors } from '../../store/authors/thunk';
const CourseInfo = () => {
useEffect(() => {
dispatch(getAuthors());
dispatch(getCourses());
}, []);
const dispatch = useDispatch();
const { courseId } = useParams();
const courses = useSelector(selectCourses);
const authors = useSelector(selectAuthors);
const course = courses.find((course) => course.id === courseId);
const createdDate = transformDate(course.creationDate);
const duration = pipeDuration(course.duration);
const courseAuthors = course.authors.map((authorId) => {
return authors.find(({ id }) => id === authorId);
});
const courseAuthorsList = courseAuthors.map((author, index, array) => {
return index + 1 === array.length ? author.name : author.name + ', ';
});
return (
<div className='container'>
<div className={classes.wrapper}>
<Link to='/courses'>{BACK_TO_COURSES}</Link>
<h2 className={classes.title}>{course.title}</h2>
<div className={classes.info}>
<p className={classes.description}>{course.description}</p>
<div className={classes.details}>
<div><strong>ID: </strong>{courseId}</div>
<div><strong>Duration: </strong>{duration} hours</div>
<div><strong>Created: </strong>{createdDate}</div>
<div><strong>Authors: </strong>
<div className={classes.authorsWrapper}>
{courseAuthorsList}
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default CourseInfo;
How can I initialize courses
const before render?
Issue
The issue here is that the
CourseInfo
component isn't being very defensive about protecting itself against potentially undefined values. Assuming the selectedcourses
state is an array you should keep in mind thatArray.prototype.find
returnsundefined
when no array element is matched back the predicate callback function.The
useEffect
hook runs after the component is rendered to the DOM during the "commit phase".Your current code:
Solution
A simple solution would be to check for a defined
courses
state value prior to attempting to access into the object.