Implement react-intersection-observer to facilitate infinite scroll

Uses react-intersection-observer to load more comments when the last of the previously loaded comments is in the viewport.
This commit is contained in:
Aaron William Po
2023-04-09 18:41:58 -04:00
parent 8981bcb4b8
commit 915adb722a
12 changed files with 157 additions and 109 deletions

View File

@@ -8,11 +8,13 @@ import { FC, useContext } from 'react';
import { Rating } from 'react-daisyui';
import { FaEllipsisH } from 'react-icons/fa';
import { useInView } from 'react-intersection-observer';
import { z } from 'zod';
interface CommentCardProps {
comment: z.infer<typeof BeerCommentQueryResult>;
mutate: ReturnType<typeof useBeerPostComments>['mutate'];
ref?: ReturnType<typeof useInView>['ref'];
}
const CommentCardDropdown: FC<CommentCardProps> = ({ comment, mutate }) => {
@@ -42,16 +44,10 @@ const CommentCardDropdown: FC<CommentCardProps> = ({ comment, mutate }) => {
className="dropdown-content menu rounded-box w-52 bg-base-100 p-2 shadow"
>
<li>
{isCommentOwner ? (
<button onClick={handleDelete}>Delete</button>
) : (
<button>Report</button>
)}
</li>
</ul>
@@ -59,52 +55,51 @@ const CommentCardDropdown: FC<CommentCardProps> = ({ comment, mutate }) => {
);
};
const CommentCardBody: FC<CommentCardProps>
= ({ comment, mutate }) => {
const { user } = useContext(UserContext);
const CommentCardBody: FC<CommentCardProps> = ({ comment, mutate, ref }) => {
const { user } = useContext(UserContext);
const timeDistance = useTimeDistance(new Date(comment.createdAt));
const timeDistance = useTimeDistance(new Date(comment.createdAt));
return (
<div className="card-body animate-in fade-in-10">
<div className="flex flex-col justify-between sm:flex-row">
<div>
<h3 className="font-semibold sm:text-2xl">
<Link href={`/users/${comment.postedBy.id}`} className="link-hover link">
{comment.postedBy.username}
</Link>
</h3>
<h4 className="italic">
posted{' '}
<time
className="tooltip tooltip-bottom"
data-tip={format(new Date(comment.createdAt), 'MM/dd/yyyy')}
>
{timeDistance}
</time>{' '}
ago
</h4>
</div>
{user && <CommentCardDropdown comment={comment} mutate={mutate} />}
return (
<div className="card-body animate-in fade-in-10" ref={ref}>
<div className="flex flex-col justify-between sm:flex-row">
<div>
<h3 className="font-semibold sm:text-2xl">
<Link href={`/users/${comment.postedBy.id}`} className="link-hover link">
{comment.postedBy.username}
</Link>
</h3>
<h4 className="italic">
posted{' '}
<time
className="tooltip tooltip-bottom"
data-tip={format(new Date(comment.createdAt), 'MM/dd/yyyy')}
>
{timeDistance}
</time>{' '}
ago
</h4>
</div>
<div className="space-y-1">
<Rating value={comment.rating}>
{Array.from({ length: 5 }).map((val, index) => (
<Rating.Item
name="rating-1"
className="mask mask-star cursor-default"
disabled
aria-disabled
key={index}
/>
))}
</Rating>
<p>{comment.content}</p>
</div>
{user && <CommentCardDropdown comment={comment} mutate={mutate} />}
</div>
);
};
<div className="space-y-1">
<Rating value={comment.rating}>
{Array.from({ length: 5 }).map((val, index) => (
<Rating.Item
name="rating-1"
className="mask mask-star cursor-default"
disabled
aria-disabled
key={index}
/>
))}
</Rating>
<p>{comment.content}</p>
</div>
</div>
);
};
export default CommentCardBody;