TypeError issues and cannot define Identifier

23 Views Asked by At

I am creating an app where users can post, comment, like, and unlike another user's post. Everything works great but while I am in a post and refresh that page, I get an error that the id in post.id is undefined. I then remove the id from post.id -- I get another error, title in post.title is undefined and it goes on.

I am fairly new to programming so this might be a 'duhh' thing but I'm so frustrated because I don't get what's going on.

Any help is really appreciated.

App.js

import './App.css';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Navbar from './pages/Navbar';
import LoginPage from './pages/LoginPage';
import PostList from './posts/PostList';
import PostDetail from './posts/PostDetail';
import EditPost from './posts/EditPost';
import Home from './pages/Home';

function App() {

  return (
    <BrowserRouter>
    <Navbar />
    <div className="App">
      <Routes>
        <Route path="/posts" element={<PostList />} />
        <Route path="/posts/:id/edit" element={<EditPost/>} />
        <Route path="/posts/:id" element={<PostDetail />} />
        <Route path="/home" element={<Home />} />
        <Route path="/" element={<LoginPage />} />
      </Routes>
    </div>
    </BrowserRouter>
  );
}

export default App;

PostDetail.js

import { useContext, useEffect, useState } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
import { ContentContext } from "../context/ContentContext";
import { UserContext} from "../context/UserContext";
import CommentList from "../comments/CommentList";
import { ErrorContext } from "../context/ErrorContext";

function PostDetail () {
    const { setErrors } = useContext(ErrorContext);
    const { user } = useContext(UserContext);
    const { contents, deletePost } = useContext(ContentContext);
    const id = parseInt(useParams().id);
    const post = contents.find(post => post.id === id);
    const navigate = useNavigate();
    const [commentMode, setCommentMode] = useState(false);
    const openComment = () => setCommentMode(commentMode => !commentMode);
    const [liked, setLiked] = useState(false);
    const params = useParams();

    useEffect(() => {
        fetch(`/posts/${post.id}/likes`)
        .then(resp => {
            if (resp.ok) {
                resp.json().then(data => {
                    setLiked(data.liked)
                })
            }
        })
        .catch(error => {
            setErrors(error)
        })
    }, [post, setErrors])

    const handleLike = () => {
        fetch(`/posts/${post.id}/likes`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
        })
        .then(resp => resp.json())
        .then(data => {
            if (data.success) {
                setLiked(true);
            }
        })
        .catch(error => {
            setErrors(error)
        });
    }

    const handleUnlike = () => {
        fetch(`/posts/${post.id}/likes/${params.id}`, {
            method: 'DELETE',
            headers: {
                'Content-Type': 'application/json',
            },
        })
        .then(resp => resp.json())
        .then(data => {
            if (data.success) {
                setLiked(false);
            }
        })
        .catch(error => {
            setErrors(error)
        });
    }

    const onDeletePost = () => {
        fetch(`/posts/${post.id}`, {
            method: "DELETE",
        })
        .then(resp => resp.json())
        .then(deletePost(post.id))
        .then(navigate(`/posts`))
    }

    return (
        <div>
            <div className="box-2">
                <h1>{post.title}</h1>
                <h5>{post.creator.username}</h5>
                <p>{post.content}</p>
                {liked ? (
                    <button className="edit-btn" onClick={handleUnlike}>Unlike</button>
                ):(
                    <button className="edit-btn" onClick={handleLike}>Like</button>
                )}
                <button className="edit-btn" onClick={openComment}>Comments</button>
                {user && user.username === post.creator?.username && (
                    <>
                    <button className="edit-btn"><Link to={`/posts/${post.id}/edit`}>Edit</Link></button>
                    <button className="edit-btn" onClick={onDeletePost}>Delete</button>
                    </>
                )}
                <br /><br />
            </div>
            <br />
            <hr />
            <br />
            <div>
                {commentMode && <CommentList post={post}/>}
            </div>
        </div>
    )
}

export default PostDetail;

I believe the problem is somewhere in these two files.

1

There are 1 best solutions below

1
Deykun On

get an error that the id in post.id is undefined. I then remove the id from post.id -- I get another error, title in post.title is undefined and it goes on.

Your post is empty because you have not fetched it yet, or it doesn't exist.

const post = contents.find(post => post.id === id); returns undefined when id is not found in the array.

Just check if post exists before rendering it:

if (!post) {
    return (<p>Loading... (or not found)</p>);
}

return (
    <div>
        <div className="box-2">

Also, hooks should be utilized directly within the component body. Wrapping them in additional functions breaks the pattern. (use... is a special prefix in React)

So instead of:

const id = parseInt(useParams().id);

Do:

const { id: paramId } = useParams();
const id = parseInt(paramId);