NextJS 13 APP routing - anti pattern - weird behavior
Unanswered
Siberian posted this in #help-forum

SiberianOP
I'm wondering if I am doing some leakage/incorrect practices in NextJS.
The functionality that I want to happen is
Comment is added via form -> Action is triggered on server -> new comment is added into db -> page is refreshed
It works, but if I change the code in page.tsx and add a single line at the top:
'use server';
I get an error saying you cant pass event listeners to functions... Which is really strange, I heard that all the components inside of the app directory are server by default.
Also, if I don't declare videos outside of the component:
And instead declare the variable here
I'm getting strange errors upon hitting the submit button. What is going on?
app/page.tsx
app/components/AddComment.tsx
The functionality that I want to happen is
Comment is added via form -> Action is triggered on server -> new comment is added into db -> page is refreshed
It works, but if I change the code in page.tsx and add a single line at the top:
'use server';
I get an error saying you cant pass event listeners to functions... Which is really strange, I heard that all the components inside of the app directory are server by default.
Also, if I don't declare videos outside of the component:
let video: Video | null = null;
And instead declare the variable here
(let) video = await videosDao.getVideoWithCommentsById(params.id);
I'm getting strange errors upon hitting the submit button. What is going on?
app/page.tsx
let video: Video | null = null;
const VideoPage: NextPage<Props> = async ({ params }) => {
// Assume you have fetched video, comments, and related videos
// pass them to their respective components as props
video = await videosDao.getVideoWithCommentsById(params.id);
const addComment = async (data: FormData) => {
'use server';
try{
let inserted = await commentsDao.insertComment(comment);
video?.comments?.push(comment as Comment);
revalidatePath(`/video/${videoId}/${video?.name}`);
}
const relatedVideos = await videosDao.getRelatedVideos(video);
return (
<div className="grid lg:grid-cols-4 gap-4 mt-2 md:grid-cols-1">
<AddComment onAddComment={addComment}/>
</div>
)
}
export default VideoPage;
app/components/AddComment.tsx
'use client';
const AddComment: React.FC<AddCommentProps> = ({ onAddComment }) => {
return (
<div className="flex flex-row space-x-4 lg:w-11/12 md:w-full p-4 shadow rounded bg-gray-800">
<form action={onAddComment} className="flex flex-row space-x-4 flex-grow">
<div className="flex-1">......
5 Replies

SiberianOP
A side question:
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault(); // This prevents the default form submission behavior
startTransition( async () => {
// Create FormData instance
const data = new FormData(event.currentTarget);
// Call the server action
let res = await onAddComment(data);
// Display the error message if it exists
if(res.error) {
setError(res.error.charAt(0).toUpperCase() + res.error.slice(1));
} else {
setError('');
}
// If the comment was successfully added, reset the input fields
if(res.success) {
setComment('');
setNickname('');
}
});
};
If I change the code in AddComment in this way, where I'm taking a server function and calling it onSubmit, is this an antipattern and is my parent component (page.tsx) still a server page?
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault(); // This prevents the default form submission behavior
startTransition( async () => {
// Create FormData instance
const data = new FormData(event.currentTarget);
// Call the server action
let res = await onAddComment(data);
// Display the error message if it exists
if(res.error) {
setError(res.error.charAt(0).toUpperCase() + res.error.slice(1));
} else {
setError('');
}
// If the comment was successfully added, reset the input fields
if(res.success) {
setComment('');
setNickname('');
}
});
};
If I change the code in AddComment in this way, where I'm taking a server function and calling it onSubmit, is this an antipattern and is my parent component (page.tsx) still a server page?

SiberianOP
Thanks, so I just confused that with the 'use client' directive, which does mark the component as client sided and allows for the usage of useState etc?

@Siberian A side question:
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault(); // This prevents the default form submission behavior
startTransition( async () => {
// Create FormData instance
const data = new FormData(event.currentTarget);
// Call the server action
let res = await onAddComment(data);
// Display the error message if it exists
if(res.error) {
setError(res.error.charAt(0).toUpperCase() + res.error.slice(1));
} else {
setError('');
}
// If the comment was successfully added, reset the input fields
if(res.success) {
setComment('');
setNickname('');
}
});
};
If I change the code in AddComment in this way, where I'm taking a server function and calling it onSubmit, is this an antipattern and is my parent component (page.tsx) still a server page?

This is not an antipattern :), and it is documented here by Next.js: https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions#custom-invocation-using-starttransition