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
CourseInfocomponent isn't being very defensive about protecting itself against potentially undefined values. Assuming the selectedcoursesstate is an array you should keep in mind thatArray.prototype.findreturnsundefinedwhen no array element is matched back the predicate callback function.The
useEffecthook 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
coursesstate value prior to attempting to access into the object.