I am trying to build a custom material-ui dialog form which uses react-hook-form to validate data.
So, I have two components.
Datatable: It gets data from other components and renders them. Also, attaches methods for different actions: delete, edit or view.
Course: It simply fetches the courses and passes the data to Datatable. It also defines the methods to delete, edit or view.
Passing a function to delete was pretty easy as it only makes an api call. So, I used this pacakge and it worked.
But editing/viewing needs a form which also should validate the data.
I thought to create a function handleView which takes the current row data and passes them to a a function which then returns the component.
This function was being called, but Course component needs to be re-render which is not possible without updating any state.
Also, there is force render but react itself discourages to use.
How can I create this custom reusable material dialog form with react-hook-form validations?
Course.jsx
const Course = () => {
const { control, handleSubmit } = useForm({
resolver: yupResolver(schema),
mode: 'all',
});
const confirm = useConfirm();
const entity = 'courses';
const { fetch: fetchCourse, response: courses = [] } = useAxios(ApiConfig.COURSE.GET_COURSES);
const { fetch } = useAxios(COURSE_UPDATE_AXIOS_CONFIG, false);
const handleDeactivate = (courseId) => {
confirm({ description: 'Do you want to deactivate course?', confirmationText: 'Yes', title: 'Deactivate Course!' })
.then(async () => {
COURSE_UPDATE_AXIOS_CONFIG.url = `${COURSE_UPDATE_AXIOS_CONFIG.url}/${courseId}`;
COURSE_UPDATE_AXIOS_CONFIG.data = {
isActive: false,
};
console.log(COURSE_UPDATE_AXIOS_CONFIG);
await fetch();
await fetchCourse();
})
.catch((error) => {
console.log(error);
});
};
const handleView = (course) => {
if (course) {
return (
<FormDialog>
<Box component="form" noValidate autoComplete="off" onSubmit={handleSubmit()}>
<Grid container spacing={4} textAlign="center">
<Grid item xs={4}>
<ControlledTextInput name={'name'} control={control} label="Course Name" defaultValue={course.name} />
</Grid>
<Grid item xs={4}>
<ControlledTextInput name={'price'} control={control} label="Course Price" defaultValue={course.price} />
</Grid>
<Grid item xs={4}>
<ControlledTextInput
name={'duration'}
control={control}
label="Course Duration"
defaultValue={course.duration}
/>
</Grid>
</Grid>
</Box>
</FormDialog>
);
}
return course;
};
return (
<Layout>
<Box padding={2} width="100%">
<PageTitle pageTitle="Courses" addButton to="/courses/new" />
{handleView()}
<Datatable
entity={entity}
columns={courseColumns}
rows={courses}
deleteRow={handleDeactivate}
viewRow={handleView}
/>
</Box>
</Layout>
);
};
Datatable.jsx
const Datatable = ({ rows, columns, deleteRow, viewRow }) => {
const actions = [
{
field: 'actions',
type: 'actions',
flex: 2,
headerName: 'Actions',
getActions: (params) => [
<GridActionsCellItem
icon={<Visibility />}
onClick={() => viewRow(params.row)}
label="View"
color="secondary"
key={params.row.id}
/>,
<GridActionsCellItem
icon={<Edit />}
onClick={() => deleteRow(params.row.id)}
label="Delete"
color="warning"
key={params.row.name}
/>,
<GridActionsCellItem
icon={<Delete />}
onClick={() => deleteRow(params.row.id)}
label="Delete"
color="error"
key={params.row.description}
/>,
],
},
];
return (
<Box
sx={{
boxShadow: '2px 4px 10px 1px rgba(201, 201, 201, 0.47)',
borderRadius: '10px',
padding: '20px',
}}
>
<DataGrid
sx={{
padding: 2,
}}
className="datagrid"
rows={rows}
columns={columns.concat(actions)}
pageSize={15}
rowsPerPageOptions={[15]}
autoHeight
components={{
Toolbar: GridToolbar,
LoadingOverlay: LinearProgress,
}}
density="comfortable"
checkboxSelection
rowHeight={70}
/>
</Box>
);
};