I’m working with React JS and GraphQL, and I’m creating this table component. Inside the table, there are many switch components, and their values are coming from the API.

And also, here’s the respons from API :
{
"data": {
"getMenuPermissionsList": [
{
"idMenu": "1",
"menuName": "Dashboard",
"permissions": [
{
"add": false,
"view": true,
"delete": false,
"modify": false,
"export": false
}
]
},
{
"idMenu": "4",
"menuName": "Konfigurasi",
"permissions": []
},
{
"idMenu": "24",
"menuName": "Layanan Operasional",
"permissions": []
},
{
"idMenu": "7",
"menuName": "Layanan Pasien",
"permissions": [
{
"add": false,
"view": true,
"delete": false,
"modify": false,
"export": false
}
]
}
]
}
}
Problem
I am using react-hook-form library for receiving default values from permissions that will be render to switch component :
const history = useHistory();
const { data: getMenuPerms, loading: getMenuPermsLoading, error: getMenuPermsError } = useQuery(GET_MENU_PERMISSIONS_LOGGED_IN);
const initialValues = getMenuPerms?.getMenuPermissionsLoggedin;
useEffect(() => {
document.title = "Tambah Group Role";
}, []);
const { register, handleSubmit, control, watch } = useForm({
defaultValues: {
perms: initialValues?.flatMap((menu) =>
menu?.subMenu.flatMap((perm) =>
perm?.permissions.map((val) => ({
view: val.view,
add: val.add,
modify: val.modify,
delete: val.delete,
export: val.export,
permission: val.permission
}))
)
)
}
});
const { fields } = useFieldArray({
name: "perms",
control
});
useEffect(() => {
console.log(`permswatch: ${watch("perms")}`);
}, [watch]);
And then, the initialValues and fields becomes value for TableRole props.
<TableRole
checked={initialValues}
fields={fields}
register={register}
/>
And the result comes like this :

Here is the complete code :
formKontrolHakAksesTambah.js
import React, { useState, useEffect, useReducer } from "react";
import { Row, Col, Card, Container } from "react-bootstrap";
import { FormCreateGroup } from "../../../component/GrupDanHakAkses/Form";
import { useMutation, useQuery } from "@apollo/client";
import { CREATE_USER_GROUP, ASSIGN_PERMS } from "../../../gql/mutation";
import { GET_ALL_USER_GROUP, GET_MENU_PERMISSIONS_LOGGED_IN } from "../../../gql/query";
import { FaSave } from "react-icons/fa";
import Swal from "sweetalert2";
import { useHistory } from "react-router-dom";
import { Loading } from "../../../component/Common";
import styles from "./formAkses.module.scss";
import { TableRole } from "../../../component/GrupDanHakAkses/Table";
import Divider from "../../../component/Common/Page/Divider";
import ButtonSecondary from "../../../component/Common/Button/ButtonSecondary";
import { useForm, useFieldArray } from "react-hook-form";
import ButtonPrimary from "../../../component/Common/Button/ButtonPrimary";
const FormKontrolDanHakAksesTambah = () => {
const history = useHistory();
const { data: getMenuPerms, loading: getMenuPermsLoading, error: getMenuPermsError } = useQuery(GET_MENU_PERMISSIONS_LOGGED_IN);
const initialValues = getMenuPerms?.getMenuPermissionsLoggedin;
useEffect(() => {
document.title = "Tambah Group Role";
}, []);
const { register, handleSubmit, control, watch } = useForm({
defaultValues: {
perms: initialValues?.flatMap((menu) =>
menu?.subMenu.flatMap((perm) =>
perm?.permissions.map((val) => ({
view: val.view,
add: val.add,
modify: val.modify,
delete: val.delete,
export: val.export,
permission: val.permission
}))
)
)
}
});
const { fields } = useFieldArray({
name: "perms",
control
});
useEffect(() => {
console.log(`permswatch: ${watch("perms")}`);
}, [watch]);
// state for input form group and switches
const [value, setValue] = useState({
groupId: "",
groupName: "",
groupDesc: "",
});
const onChange = (event) => {
setValue({
...value,
[event.target.name]: event.target.value,
});
};
const [createUserGroup, { loading: loadingCreateUserGroup }] = useMutation(
CREATE_USER_GROUP,
{
onCompleted: () => {
history.push("/konfigurasi/grup-dan-hak-akses-pengguna");
},
onError: (err) => {
console.error(err.message);
},
}
);
const [assignPermission, { loading: assignPermsLoading }] = useMutation(
ASSIGN_PERMS,
{
onCompleted: (data) => {
console.log(data);
},
onError: (err) => {
console.error(JSON.stringify(err, null, 2));
},
}
);
if (loadingCreateUserGroup || assignPermsLoading)
return (
<>
<Loading />
</>
);
const handleSubmitGroupBaru = async (e) => {
e.preventDefault();
if (
value.groupId === "" ||
value.groupName === "" ||
value.groupDesc === ""
) {
// Menampilkan pesan error jika ada field yang kosong
Swal.fire({
icon: "error",
title: "Silakan lengkapi semua field",
});
return;
}
try {
// Membuat promise untuk mutasi createUserGroup
const createGroupPromise = createUserGroup({
variables: {
input: {
groupId: value.groupId,
groupName: value.groupName,
groupDesc: value.groupDesc,
},
},
awaitRefetchQueries: true,
refetchQueries: [{ query: GET_ALL_USER_GROUP }, "getAllUserGroup"],
});
// Menunggu hasil promise mutasi createUserGroup
const {
data: {
createUserGroup: { groupId },
},
} = await createGroupPromise;
// Membuat promise untuk mutasi assignPermission
const assignPermissionPromise = assignPermission({
variables: {
input: {
groupId: groupId,
permissionCodes: []
},
},
});
// Menunggu hasil promise mutasi assignPermission
await assignPermissionPromise;
Swal.fire({
icon: "success",
title: "Akun Grup berhasil ditambahkan",
showConfirmButton: false,
timer: 1500,
});
} catch (err) {
Swal.fire({
icon: "error",
title: err.message,
});
}
};
return (
<>
<section className={`${styles.FormAksi}`}>
<Container className={`${styles.container}`}>
<Row>
<Col>
<Card className={`${styles.customCard}`}>
<Card.Title className={`${styles.customCardHeader}`}>
<p className="text-uppercase base-lg text-semi-bold">
Informasi Grup Akun
</p>
</Card.Title>
<Card.Body>
<FormCreateGroup onChange={onChange} value={value} />
</Card.Body>
</Card>
</Col>
</Row>
<Row>
<Col>
<Card className="border-0 mt-5">
<Card.Title>
<p className="text-uppercase base-lg text-semi-bold mt-2 mx-2">
Kontrol Akses
</p>
</Card.Title>
<Card.Body>
{ getMenuPermsLoading && <Loading/> }
{ getMenuPermsError && <p>{getMenuPermsError.message}</p> }
<TableRole
checked={initialValues}
fields={fields}
register={register}
/>
</Card.Body>
</Card>
</Col>
</Row>
</Container>
<Divider className="my-3" />
<div className="d-flex justify-content-end">
<ButtonSecondary
variant="solid"
wider="true"
onClick={handleSubmitGroupBaru}
className="mt-5"
>
{" "}
<FaSave className="mx-2" /> SIMPAN PERUBAHAN
</ButtonSecondary>
</div>
</section>
</>
);
};
export default FormKontrolDanHakAksesTambah;
TableRole.js :
import React, { Fragment, useRef, useEffect } from "react";
import { Table, Form } from "react-bootstrap";
import { useFieldArray, useForm } from "react-hook-form";
export default function TableRole({ checked, register, fields }) {
const tableHeader = [
"No",
"Menu",
"Sub Menu",
"Lihat",
"Tambah",
"Ubah",
"Hapus",
"Export"
];
return (
<Table className="table-responsive">
<thead
style={{ backgroundColor: "#ECEFF1" }}
className="txt-blue-grey-700 base-md text-bold"
>
<tr>
{tableHeader.map((header, index) => (
<th
key={index}
className="txt-blue-grey-700 base-md text-bold text-center"
style={{ padding: "0.75rem" }}
>
{header}
</th>
))}
</tr>
</thead>
<tbody className="text-center">
{checked?.map((row) => (
<React.Fragment key={row.id}>
<RoleRow
fields={fields}
register={register}
row={row}
/>
</React.Fragment>
))}
</tbody>
</Table>
);
}
const RoleRow = ({ row, register, fields, defaultValues }) => (
<>
<tr>
<td rowSpan={row.subMenu.length + 1}>{row.idMenu}</td>
<td rowSpan={row.subMenu.length + 1}>{row.menuName}</td>
</tr>
{
row.subMenu.map((subMenuItem) => (
<>
<tr key={subMenuItem.idMenu}>
<td>{subMenuItem.menuName}</td>
{
fields?.map((value) => (
<PermissionCheckbox value={value} register={register} fields={fields} />
))
}
</tr>
</>
))
}
</>
);
const PermissionCheckbox = ({ fields, register, value }) => {
return (
<>
{
fields.map((item, index) => {
return (
<Fragment key={`perms.${index}.permission`}>
<td>
<Form.Check
id={`lihat-${item.id}`}
type="switch"
value={value}
{...register(`perms.${index}.view`)}
/>
</td>
<td>
<Form.Check
id={`tambah-${item.id}`}
type="switch"
{...register(`perms.${index}.add`)}
/>
</td>
<td>
<Form.Check
id={`ubah-${item.id}`}
type="switch"
{...register(`perms.${index}.modify`)}
/>
</td>
<td>
<Form.Check
id={`hapus-${item.id}`}
type="switch"
{...register(`perms.${index}.delete`)}
/>
</td>
<td>
<Form.Check
id={`export-${item.id}`}
type="switch"
{...register(`perms.${index}.export`)}
/>
</td>
</Fragment>
)
})
}
</>
);
};
Question
How can I handle default values from the parent and pass the data to the child component (TableRole) using react-hook-form? Additionally, how can the TableRole component read the data that is coming from the API ?