// server-action을 사용할 form.
export default function GptQuestionForm({ selectedChatRoom }: Props) {
const inputRef = useRef<HTMLInputElement | null>(null)
const handleCreateInquiry = useCallback(
async (formData: FormData) => {
try {
if (inputRef.current) inputRef.current.value = ''
await onCreateInquiry(formData, selectedChatRoom) // server-action
} catch (error) {
// error handling
}
}, [selectedChatRoom])
return (
<form action={handleCreateInquiry}>
{selectedChatRoom && <RelayQuestionCheckbox />}
<ChatInput inputRef={inputRef} />
<SubmitButton />
</form>
)
}
// gptInquiryAction.ts
'use server'
export const onCreateInquiry = async (formData: FormData, selectedChatRoom: ChatRoom | null) => {
// formDat는 아래와 같이 사용할 수 있다
const userQuestion = formData.get('question')?.toString()
const isRelay = formData.has('relay-question') && formData.get('relay-question') === 'on'
if (!userQuestion) return
let completion
if (isRelay) {
const chatlistResponse = await getChats({ roomSeq: selectedChatRoom?.roomSeq || '', page: 1, size: 100 }) // 또 다른 서버액션
// ...
} else {
// ...
}
try {
const message: string = completion.choices[0].message.content as string
let roomSeq = ''
!selectedChatRoom
? (roomSeq = await onCreateChatRoom(userQuestion.substring(0, 20))) // 또 다른 서버액션
: (roomSeq = selectedChatRoom.roomSeq)
await onCreateChat({
roomSeq,
answer: message,
question: userQuestion,
}) // 또 다른 서버액션
return message
} catch (error) {
return { role: 'assistant', content: '요청에 실패하였습니다.' }
}
}
function ChatInput({ inputRef }: { inputRef: RefObject<HTMLInputElement> }, _: never) {
const { pending } = useFormStatus() // observe server-action. action, data, method 프로퍼티도 존재한다
// pending으로 상태 감지
return (
<>
{pending ? (
<div>
<Typography>
✨ 잠시만 기다려주세요! ✨
</Typography>
</div>
) : (
<input
ref={inputRef}
name='question'
type='text'
placeholder='질문을 입력해주세요.'
/>
)}
</>
)
}
export default forwardRef(ChatInput)
3줄 요약
1. form UI 작성
2. form에서 사용할 serveraction 작성
3. useFormStatus를 통해 상태를 관찰하여 error, loading status handling
서버액션 사용시 적절한 revalidateTags, revalidatePath를 통해 데이터를 리패칭해야 한다.