refactor(FE): Refactor form components to improve state handling

This commit is contained in:
rstubryan
2026-03-05 15:59:32 +07:00
parent 333dd01f92
commit 9ff6f3a35d
3 changed files with 47 additions and 38 deletions
@@ -1,6 +1,6 @@
'use client'; 'use client';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import useSWR from 'swr'; import useSWR from 'swr';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
@@ -75,6 +75,12 @@ const ExpenseKandangsTable = ({
.filter((id): id is number => id !== undefined) .filter((id): id is number => id !== undefined)
) )
); );
const rowSelectionRef = useRef(rowSelection);
const prevRowSelectionRef = useRef<Record<string, boolean>>({});
useEffect(() => {
rowSelectionRef.current = rowSelection;
}, [rowSelection]);
const kandangsColumns: ColumnDef<Kandang>[] = [ const kandangsColumns: ColumnDef<Kandang>[] = [
{ {
@@ -133,10 +139,19 @@ const ExpenseKandangsTable = ({
useEffect(() => { useEffect(() => {
setOpen(isResponseSuccess(kandangs) ? kandangs.data.length > 0 : false); setOpen(isResponseSuccess(kandangs) ? kandangs.data.length > 0 : false);
}, [kandangs, isResponseSuccess]); }, [kandangs]);
useEffect(() => { useEffect(() => {
if (Object.keys(rowSelection).length !== 0 && isResponseSuccess(kandangs)) { const currentKeys = Object.keys(rowSelection).sort().join(',');
const prevKeys = Object.keys(prevRowSelectionRef.current).sort().join(',');
if (currentKeys !== prevKeys) {
prevRowSelectionRef.current = { ...rowSelection };
if (
Object.keys(rowSelection).length !== 0 &&
isResponseSuccess(kandangs)
) {
const formattedSelectedKandangs = Object.keys(rowSelection).map( const formattedSelectedKandangs = Object.keys(rowSelection).map(
(item) => { (item) => {
const selectedKandang = kandangs.data.find( const selectedKandang = kandangs.data.find(
@@ -151,15 +166,16 @@ const ExpenseKandangsTable = ({
); );
onChange(formattedSelectedKandangs); onChange(formattedSelectedKandangs);
} else { } else if (Object.keys(rowSelection).length === 0) {
onChange([]); onChange([]);
} }
}, [rowSelection]); }
}, [rowSelection, kandangs, onChange]);
useEffect(() => { useEffect(() => {
if ( if (
selectedKandangs.length === 0 && selectedKandangs.length === 0 &&
Object.keys(rowSelection).length !== 0 Object.keys(rowSelectionRef.current).length !== 0
) { ) {
setRowSelection({}); setRowSelection({});
} }
@@ -1,6 +1,6 @@
'use client'; 'use client';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useState } from 'react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useFormik } from 'formik'; import { useFormik } from 'formik';
import toast from 'react-hot-toast'; import toast from 'react-hot-toast';
@@ -90,6 +90,7 @@ const ExpenseRealizationForm = ({
const formik = useFormik<ExpenseRealizationFormValues>({ const formik = useFormik<ExpenseRealizationFormValues>({
initialValues: getExpenseRealizationFormInitialValues(initialValues), initialValues: getExpenseRealizationFormInitialValues(initialValues),
enableReinitialize: true,
validationSchema: validationSchema:
type === 'edit' type === 'edit'
? UpdateExpenseRealizationFormSchema ? UpdateExpenseRealizationFormSchema
@@ -143,7 +144,6 @@ const ExpenseRealizationForm = ({
}, },
}); });
const { setValues: formikSetValues } = formik;
const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik);
const { const {
@@ -254,10 +254,6 @@ const ExpenseRealizationForm = ({
formik.setFieldValue('documents', newRequestDocuments); formik.setFieldValue('documents', newRequestDocuments);
}; };
useEffect(() => {
formikSetValues(getExpenseRealizationFormInitialValues(initialValues));
}, [formikSetValues, getExpenseRealizationFormInitialValues, initialValues]);
return ( return (
<section className='w-full'> <section className='w-full'>
<header className='flex flex-col gap-4'> <header className='flex flex-col gap-4'>
@@ -1,6 +1,6 @@
'use client'; 'use client';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useState } from 'react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useFormik } from 'formik'; import { useFormik } from 'formik';
import { toast } from 'react-hot-toast'; import { toast } from 'react-hot-toast';
@@ -102,6 +102,7 @@ const ExpenseRequestForm = ({
const formik = useFormik<ExpenseRequestFormValues>({ const formik = useFormik<ExpenseRequestFormValues>({
initialValues: getExpenseFormInitialValues(initialValues), initialValues: getExpenseFormInitialValues(initialValues),
enableReinitialize: true,
validationSchema: validationSchema:
type === 'edit' type === 'edit'
? UpdateExpenseRequestFormSchema ? UpdateExpenseRequestFormSchema
@@ -171,7 +172,7 @@ const ExpenseRequestForm = ({
}, },
}); });
const { setValues: formikSetValues } = formik; const { setFieldValue, setFieldTouched } = formik;
const { const {
setInputValue: setLocationInputValue, setInputValue: setLocationInputValue,
@@ -186,8 +187,8 @@ const ExpenseRequestForm = ({
} = useSelect<Supplier>(SupplierApi.basePath, 'id', 'name'); } = useSelect<Supplier>(SupplierApi.basePath, 'id', 'name');
const categoryChangeHandler = (val: OptionType | OptionType[] | null) => { const categoryChangeHandler = (val: OptionType | OptionType[] | null) => {
formik.setFieldTouched('category', true); setFieldTouched('category', true);
formik.setFieldValue('category', val); setFieldValue('category', val);
}; };
const locationChangeHandler = useCallback( const locationChangeHandler = useCallback(
@@ -195,12 +196,12 @@ const ExpenseRequestForm = ({
const location = val as OptionType | null; const location = val as OptionType | null;
const locationId = location ? Number(location.value) : 0; const locationId = location ? Number(location.value) : 0;
formik.setFieldTouched('location', true); setFieldTouched('location', true);
formik.setFieldValue('location', location); setFieldValue('location', location);
formik.setFieldTouched('location_id', true); setFieldTouched('location_id', true);
formik.setFieldValue('location_id', locationId); setFieldValue('location_id', locationId);
}, },
[] [setFieldTouched, setFieldValue]
); );
const kandangsChangeHandler = ( const kandangsChangeHandler = (
@@ -343,10 +344,6 @@ const ExpenseRequestForm = ({
formik.handleSubmit(e); formik.handleSubmit(e);
}; };
useEffect(() => {
formikSetValues(getExpenseFormInitialValues(initialValues));
}, [formikSetValues, getExpenseFormInitialValues, initialValues]);
return ( return (
<> <>
<section className='w-full'> <section className='w-full'>