[英]How to get data from store before render in React-redux?
I need to render component by route "courses/:courseId"
, but I got an error "Uncaught TypeError: Cannot read properties of undefined".我需要通过路由
"courses/:courseId"
渲染组件,但出现错误“Uncaught TypeError: Cannot read properties of undefined”。 It's because courses
is empty just after render.这是因为
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;
How can I initialize courses
const before render?如何在渲染之前初始化
courses
常量?
The issue here is that the CourseInfo
component isn't being very defensive about protecting itself against potentially undefined values.这里的问题是
CourseInfo
组件在保护自己免受潜在未定义值的影响方面并不是很有防御性。 Assuming the selected courses
state is an array you should keep in mind that Array.prototype.find
returns undefined
when no array element is matched back the predicate callback function.假设所选
courses
状态是一个数组,您应该记住,当没有数组元素与谓词回调函数匹配时, Array.prototype.find
返回undefined
。
Return value
返回值
The first element in the array that satisfies the provided testing function.
满足提供的测试函数的数组中的第一个元素。 Otherwise,
undefined
is returned.否则,返回
undefined
。
The useEffect
hook runs after the component is rendered to the DOM during the "commit phase". useEffect
挂钩在组件在“提交阶段”呈现给 DOM 后运行。
Your current code:您当前的代码:
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>
);
};
A simple solution would be to check for a defined courses
state value prior to attempting to access into the object.一个简单的解决方案是在尝试访问对象之前检查定义的
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>
);
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.