如何在React-redux渲染之前从存储中获取数据?



我需要通过路由"courses/:courseId"渲染组件,但我得到了一个错误" Uncaught TypeError: Cannot read properties of undefined"这是因为courses在渲染后是空的。

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;

如何在渲染前初始化coursesconst ?

Issue

这里的问题是CourseInfo组件在保护自己免受潜在未定义值的侵害方面并不是非常具有防御性。假设选择的courses状态是一个数组,您应该记住,当没有数组元素与谓词回调函数匹配时,Array.prototype.find返回undefined

返回值数组中满足所提供测试的第一个元素函数。否则返回undefined

useEffect钩子在"提交阶段"将组件呈现给DOM之后运行。

当前代码:

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); // <-- potentially undefined
const createdDate = transformDate(course.creationDate); // <-- potential undefined access
const duration = pipeDuration(course.duration); // <-- potential undefined access
const courseAuthors = course.authors.map((authorId) => { // <-- potential undefined access
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} // <-- potential undefined access
</h2>
<div className={classes.info}>
<p className={classes.description}>
{course.description} // <-- potential undefined access
</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>
);
};
<标题>

解决方案一个简单的解决方案是在尝试访问对象之前检查已定义的courses状态值。

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);
// Check for falsey course value
if (!course) {
return <div>No courses found.</div>;
}
const createdDate = transformDate(course.creationDate);
const duration = pipeDuration(course.duration);
// Guard against undefined course.authors and author arrays
const courseAuthors = (course.authors || [])
// Map found author objects
.map((authorId) => (authors || []).find(({ id }) => id === authorId))
// Filter any undefined "holes" for unknown authors
.filter(Boolean)
// Map to author's name property
.map((author) => author.name)
// Join into comma-separated list string
.join(", ");
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}>
{courseAuthors}
</div>
</div>
</div>
</div>
</div>
</div>
);
};

最新更新