Component Pattern
Controlled / Uncontrolled Component
Controlled Component
Controlled components are form elements (like
input
,textarea
, orselect
) that are managed by React state.
import React, { useState } from 'react';
function ControlledComponent() {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
alert('A name was submitted: ' + value);
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={value} onChange={handleChange} />
</label>
<button type="submit">Submit</button>
</form>
);
}
export default ControlledComponent;
Uncontrolled Component
Uncontrolled components in React manage their own state internally rather than relying on React state.
Using the
ref
attribute to create a reference (this.inputRef
) to the DOM node of the input field to access the internal state
import React, { useRef } from 'react';
function UncontrolledComponent() {
const inputRef = useRef(null); // Create a ref to hold the input DOM element
const handleSubmit = () => {
// Access the input value using the ref
console.log(inputRef.current.value);
};
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={handleSubmit}>Submit</button>
</div>
);
}
export default UncontrolledComponent;
Pro & Con
Controlled Component
Using controlled components ensures that the form data is always in sync with the React state. This predictability comes from having a single source of truth for the data and easier to debug
Easier to integrate with form library, e.g:
React Hook Form
Uncontrolled Component
Applicable for the form that is straightforward with minimal input fields and does not require complex validation or dynamic updates based on other form inputs.
Validation logic often involves accessing and checking each input's value directly through refs (
ref.current.value
). This approach can lead to more manual and error-prone validation code, especially in forms with complex validation requirements.
Composable Component
import { createFileRoute } from "@tanstack/react-router";
import MyTable from "../../components/myTable";
export const Route = createFileRoute("/_authenticated/my-table")({
component: () => <MyTablePage />,
});
const MyTablePage = () => {
return (
<MyTable>
<MyTable.Search />
<MyTable.Table />
<MyTable.Pagination />
</MyTable>
);
};
import { ColumnDef, createColumnHelper } from "@tanstack/react-table";
import React from "react";
import { Product } from "../../types/my-table";
import Checkbox from "./checkBox";
import Row from "../layout/row";
import CustomTable from "./customTable";
import CustomSearch from "./customSearch";
import CustomPagination from "./customPagintaion";
import useMyTable from "../../hooks/my-table/useMyTable";
import TableContext from "../../contexts/tableProvider";
interface Props {
children: React.ReactNode;
}
const MyTable = ({ children }: Props) => {
const columnsHelper = createColumnHelper<Product>();
const columns: ColumnDef<Product, any>[] = [];
const { table } = useMyTable(columns);
return (
<TableContext.Provider value={{ table }}>
<div className="relative overflow-x-auto shadow-md sm:rounded-lg py-10 px-5">
{children}
</div>
</TableContext.Provider>
);
};
MyTable.Search = CustomSearch;
MyTable.Table = CustomTable;
MyTable.Pagination = CustomPagination;
export default MyTable;
Easy to implement container & presentation pattern, state management & logic is on parent component (container layer) and pass the prop into child-component (presentation layer) through implementing context provider
Easier to understand the relationship between components and clear structure
Suitable to implement it with
Form
,Table
References
Last updated
Was this helpful?