简体   繁体   中英

Cannot read properties of undefined in react using redux

I am getting this error when trying to display comments of specific posts.

Uncaught TypeError: Cannot read properties of undefined (reading 'from')

In my parent component I fixed it with calling dispatch, but here it does not work.

Parent component "Post":

import React, { FC, useEffect, useState } from 'react';
import Alert from 'react-bootstrap/esm/Alert';
import { useLocation, useParams } from 'react-router-dom';
import AddComment from 'src/components/ui/AddComment/AddComment';
import CommentSection from 'src/components/ui/CommentSection/CommentSection';
import PostContent from 'src/components/ui/PostContent/PostContent';
import PostHeader from 'src/components/ui/PostHeader/PostHeader';
import { loginSuccess } from 'src/store/actions/authActions';
import { getPosts } from 'src/store/actions/postActions';
import {useAppDispatch, useAppSelector } from 'src/store/app/hooks';

const Post : FC = () => {
  const {id} = useParams();
  const {posts, filter } = useAppSelector((state) => state.post);
  const dispatch = useAppDispatch();

  // Find post with matching id from url
  const post = posts.find(p => String(p.id) === id);

  useEffect(() => {
    dispatch(getPosts(filter));
  }, [dispatch, filter]);

  if (!post) {
    return (
    <div>
      <Alert variant="warning" style={{ width: "42rem" }}>
        <Alert.Heading>
          No posts here.
        </Alert.Heading>
      </Alert>
    </div>
  )}
  return (
    <div>
      <PostHeader header={<h2>{post.title}</h2>}>
        <div>{post.content}</div>
      </PostHeader>
      <PostContent content={<div>{post.content}</div>} />
      <AddComment id={id} />
      <CommentSection id={id} />
    </div>
  )
};

export default Post;

Child component: "Comment Section":

import React, { FC, PropsWithChildren, ReactElement, useEffect, useState } from 'react';
import instance from 'src/axios';
import { getPosts } from 'src/store/actions/postActions';
import { useAppDispatch, useAppSelector } from 'src/store/app/hooks';
import classes from './CommentSection.module.scss';

interface CommentSectionProps {
  id?: string;  
}

const CommentSection: FC<PropsWithChildren<CommentSectionProps>> = ({ id }) => {
  
  const [comment, setComment] = useState([]);

  const {posts, filter } = useAppSelector((state) => state.post);
  const dispatch = useAppDispatch();

  useEffect(() => {
    dispatch(getPosts(filter));
  }, [dispatch, filter]);

  useEffect(()=>{  instance.get(`https://breddit.equaleyes-solutions.com/posts/${id}/comment`)
  .then(function (res) { 
    console.log(res.data) 
    setComment(res.data)
    })
  .catch(function (res) { console.log(res) })},[])

  // Display Comment
  const commentDisplay = comment.map(comment => {
    return(
      <div key={comment.id} className={classes.Comment}> 
        <span style={{fontWeight: 'bold'}}>{posts.find(p => String(p.from.id) === comment.fromId).from.username}</span>
        <label>{comment.content}</label>
      </div>
    )})

  return (
    <div className={classes.Container}>
      <h4>Comments</h4>
      {commentDisplay}
    </div>
  );
};

export default CommentSection;

Does anyone have any suggestions or ideas how I can sort this error out? I would really appriceate it.

Issue

The issue here is that Array.prototype.find potentially returns undefined if no match is found.

// Display Comment
const commentDisplay = comment.map(comment => {
  return (
    <div key={comment.id} className={classes.Comment}> 
      <span style={{fontWeight: 'bold'}}>
        {posts.find(p => String(p.from.id) === comment.fromId).from.username} // <-- undefined
      </span>
      <label>{comment.content}</label>
    </div>
  );
});

Solution

Here you could simply use the Optional Chaining Operator to guard against the potentially undefined/null reference.

const [comments, setComments] = useState([]);

...

useEffect(/* effect to update comments state */);

...

// Display Comment
const commentDisplay = comments.map(comment => {
  const post = posts.find(p => String(p.from.id) === comment.fromId);
  return (
    <div key={comment.id} className={classes.Comment}> 
      <span style={{fontWeight: 'bold'}}>
        {post?.from.username} // <-- null/undefined check
      </span>
      <label>{comment.content}</label>
    </div>
  );
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM