React Forms, Controlled Components, Validation | Sinhala Guide
ආයුබෝවන් React Dev යාළුවනේ! React Forms සහ Controlled Components පහසුවෙන් ඉගෙන ගනිමු
ආයුබෝවන් යාළුවනේ! React එක්ක වැඩ කරනකොට Forms කියන්නේ ටිකක් අවුල් සහගත මාතෘකාවක් කියලා හිතෙනවද? නැත්තම් කොහොමද User ගෙන් ගන්න Input Data හරියට Manage කරන්නේ කියලා ප්රශ්නයක්ද? එහෙනම් මේ Tutorial එක ඔයාට තමයි! වෙබ් Application එකක් හදනකොට User ගෙන් Data ගන්න Forms කියන්නේ අනිවාර්ය දෙයක්. User Registration, Login, Contact Forms වගේ දේවල් වලට මේ Forms අත්යවශ්යයි.
මේ Guide එකෙන් අපි ReactJS Forms ගැන මුල සිට සරලව කතා කරනවා. විශේෂයෙන්ම Controlled Components කියන්නේ මොකක්ද, ඒවා පාවිච්චි කරන්නේ කොහොමද, State Management කරන්නේ කොහොමද, වගේම Input Validation එකක් කොහොමද කරන්නෙ කියලත් අපි ඉගෙන ගන්නවා. තවදුරටත්, අපි සරල Registration Form එකක් හදලා මේ හැම දෙයක්ම Practical විදිහට බලමු. මොකද මේක React Developer කෙනෙක් විදිහට ඔයාට අනිවාර්යයෙන්ම දැනගන්න ඕන දෙයක්!
1. Forms in React – මූලික කරුණු (The Basics)
සාමාන්ය HTML වලදී අපි Form එකක් හදන්නේ මෙහෙමයි:
<form>
<label for="name">නම:</label>
<input type="text" id="name" name="userName" />
<button type="submit">Submit</button>
</form>මේ වගේ Form එකක් Submit කරාම, Page එක Refresh වෙලා, Server එකට Data යනවා. නමුත් React වලදී අපි කැමති නැහැ හැම වෙලාවෙම Page එක Refresh වෙනවට. අපි කැමතියි User Input එක Real-time විදිහට Manage කරන්න, ඒ අනුව UI එක Update කරන්න.
React වලදී Forms වල Data හසුරුවන ප්රධාන ක්රම දෙකක් තියෙනවා: Controlled Components සහ Uncontrolled Components. මේ දෙකෙන් අපි බොහෝ වෙලාවට පාවිච්චි කරන්නේ Controlled Components. ඒ ඇයි කියලත් අපි බලමු.
2. Controlled Components – React ක්රමය
Controlled Component එකක් කියන්නේ, ඒ input element එකේ value එක React state එකකින් control කරන එක. ඒ කියන්නේ, input box එකක තියෙන දත්ත (value) මොකක්ද කියලා තීරණය කරන්නේ React Component එකේ state එකෙන්. User කෙනෙක් input එකට මොනවා හරි type කරන හැම වෙලාවෙම, ඒ value එක React state එකට Update වෙනවා.
වැදගත් ගුණාංග දෙක: value සහ onChange
value: මේpropඑකෙන්inputඑකේ වත්මන් අගය තීරණය කරනවා. මේක හැම වෙලාවෙම state එකෙන් එන්න ඕනේ.onChange: මේevent handlerඑක trigger වෙන්නේ User කෙනෙක්inputඑකකvalueඑක වෙනස් කරන හැම වෙලාවෙම. මේකෙන් තමයි අපි state එක Update කරන්නේ.
සරල උදාහරණයක් බලමු:
import React, { useState } from 'react';
function NameInput() {
const [name, setName] = useState(''); // State එකක් හදාගන්නවා
const handleChange = (event) => {
setName(event.target.value); // Input value එකෙන් state එක Update කරනවා
};
return (
<div>
<label htmlFor="name">ඔබේ නම:</label>
<input
type="text"
id="name"
value={name} // Input එකේ value එක state එකෙන් control කරනවා
onChange={handleChange} // onChange event එක handle කරනවා
/>
<p>ආයුබෝවන්, <strong>{name}</strong>!</p>
</div>
);
}
export default NameInput;මේ Code එකෙන් වෙන්නේ:
useState('')මගින්nameකියන state variable එකක් හදාගන්නවා, මුලින් හිස් string එකක් විදිහට.<input>එකේvalue={name}කියල දානවා, ඒ කියන්නේinputඑකේ වත්මන් අගය හැමවෙලාවෙමnamestate එකේ තියෙන අගයයි.onChange={handleChange}මගින් කියන්නේinputඑකට මොනවා හරි type කරාමhandleChangefunction එක ක්රියාත්මක වෙන්න ඕනේ කියලා.handleChangefunction එක ඇතුලේsetName(event.target.value)මගින්inputඑකේ අලුත් අගයnamestate එකට දානවා.
මේ ක්රමයෙන් input එකේ තියෙන හැම අකුරක්ම අපේ React state එකේ තියෙන නිසා, අපිට ඒ value එක ඕන වෙලාවක පාවිච්චි කරන්න, වෙනස් කරන්න, හෝ validate කරන්න පුළුවන්.
3. සරල Registration Form එකක් සහ Validation
දැන් අපි මේ දැනුම පාවිච්චි කරලා සරල Registration Form එකක් හදමු. මේ Form එකේ නම (Name), ඊමේල් (Email), සහ මුරපදය (Password) කියන fields තුන තියෙනවා. ඒ වගේම අපි Input Validation එකකුත් එකතු කරමු.
import React, { useState } from 'react';
function RegistrationForm() {
// State එකක් හදනවා හැම input field එකකම values ටික තියාගන්න
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
});
// State එකක් හදනවා validation errors ටික තියාගන්න
const [errors, setErrors] = useState({});
// Input changes handle කරන function එක
const handleChange = (event) => {
const { name, value } = event.target;
setFormData((prevFormData) => ({ ...prevFormData, [name]: value }));
};
// Validation කරන function එක
const validateForm = () => {
const newErrors = {};
if (!formData.name.trim()) {
newErrors.name = 'නම ඇතුළත් කරන්න.';
} else if (formData.name.length < 3) {
newErrors.name = 'නම අකුරු 3කට වඩා දිග විය යුතුයි.';
}
if (!formData.email.trim()) {
newErrors.email = 'ඊමේල් ලිපිනය ඇතුළත් කරන්න.';
} else if (!/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(formData.email)) {
newErrors.email = 'වලංගු ඊමේල් ලිපිනයක් ඇතුළත් කරන්න.';
}
if (!formData.password.trim()) {
newErrors.password = 'මුරපදයක් ඇතුළත් කරන්න.';
} else if (formData.password.length < 6) {
newErrors.password = 'මුරපදය අකුරු 6කට වඩා දිග විය යුතුයි.';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0; // Errors නැත්නම් true return කරනවා
};
// Form submit කරන function එක
const handleSubmit = (event) => {
event.preventDefault(); // Default form submission එක නවත්වනවා
if (validateForm()) {
// Validation සාර්ථක නම් මෙතනින් data process කරන්න පුළුවන්
console.log('Form Submitted Successfully:', formData);
alert(`Registration Successful for ${formData.name}!`);
// Form එක reset කරන්න ඕනිනම්:
// setFormData({ name: '', email: '', password: '' });
} else {
console.log('Form has errors.');
}
};
return (
<div style={{ maxWidth: '400px', margin: '20px auto', padding: '20px', border: '1px solid #ccc', borderRadius: '8px' }}>
<h2>අලුත් ගිණුමක් සාදන්න</h2>
<form onSubmit={handleSubmit}>
<div style={{ marginBottom: '15px' }}>
<label htmlFor="name" style={{ display: 'block', marginBottom: '5px' }}>නම:</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
style={{ width: '100%', padding: '8px', boxSizing: 'border-box', border: errors.name ? '1px solid red' : '1px solid #ddd' }}
/>
{errors.name && <p style={{ color: 'red', fontSize: '0.9em', marginTop: '5px' }}>{errors.name}</p>}
</div>
<div style={{ marginBottom: '15px' }}>
<label htmlFor="email" style={{ display: 'block', marginBottom: '5px' }}>ඊමේල් ලිපිනය:</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
style={{ width: '100%', padding: '8px', boxSizing: 'border-box', border: errors.email ? '1px solid red' : '1px solid #ddd' }}
/>
{errors.email && <p style={{ color: 'red', fontSize: '0.9em', marginTop: '5px' }}>{errors.email}</p>}
</div>
<div style={{ marginBottom: '20px' }}>
<label htmlFor="password" style={{ display: 'block', marginBottom: '5px' }}>මුරපදය:</label>
<input
type="password"
id="password"
name="password"
value={formData.password}
onChange={handleChange}
style={{ width: '100%', padding: '8px', boxSizing: 'border-box', border: errors.password ? '1px solid red' : '1px solid #ddd' }}
/>
{errors.password && <p style={{ color: 'red', fontSize: '0.9em', marginTop: '5px' }}>{errors.password}</p>}
</div>
<button type="submit"
style={{
width: '100%',
padding: '10px 15px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '1em'
}}
>ගිණුමක් සාදන්න</button>
</form>
</div>
);
}
export default RegistrationForm;මේ Code එකෙන් වෙන්නේ මොකක්ද?
- Multiple Inputs සඳහා Single State Object එකක්: අපි
useStateපාවිච්චි කරලාformDataකියනobjectඑකක් හදාගන්නවා. මේක ඇතුළේ Form එකේ හැමinputඑකකමvalueඑකkey-valueයුගලයක් විදිහට තියාගන්නවා (name: '', email: '', password: ''). - Generic
handleChangeFunction එකක්:handleChangefunction එක ඇතුලේevent.target.nameසහevent.target.valueපාවිච්චි කරලා,eventඑක trigger වුණුinputඑකේnameඑක අනුව අදාළkeyඑකේvalueඑක Update කරනවා....prevFormDataමගින් කලින් තිබ්බformDataඑකේ අගයන් එලෙසම තියාගෙන, වෙනස් වුණුinputඑකේ අගය විතරක් overwrite කරනවා. - Validation:
validateFormකියන function එකෙන් Form එකේ fields ටික validate කරනවා. හිස්ද, ඊමේල් format එක හරිද, password එකේ දිග ප්රමාණවත්ද වගේ දේවල් බලනවා. Errors තියෙනවා නම්,setErrorsමගින්errorsstate එකට ඒ Errors ටික එකතු කරනවා. - Error Messages Display කිරීම:
{errors.name && <p>{errors.name}</p>}වගේ Conditional Rendering පාවිච්චි කරලා Errors තියෙනවා නම් ඒinputඑක යටින් Error Message එක පෙන්නනවා. - Form Submission Handling:
<form>එකටonSubmit={handleSubmit}දාලා Form එක Submit කරනකොටhandleSubmitfunction එක ක්රියාත්මක කරනවා. මේක ඇතුලේevent.preventDefault()දාලා Default Browser Behavior එක (Page Refresh වෙන එක) නවත්වනවා. ඊට පස්සේvalidateForm()එක Call කරලා Form එක validate කරලා, හැම දෙයක්ම හරි නම් Data ටිකconsole.logකරනවා.
4. Uncontrolled Components – කවදාද, ඇයි?
Uncontrolled Components කියන්නේ, HTML Form elements වල Data හසුරුවන්න React state එකක් පාවිච්චි නොකරන input elements. මේවා සාමාන්ය HTML Form elements වගේම ක්රියා කරනවා. මේවායේ Data ගන්න අපි useRef Hook එක පාවිච්චි කරනවා.
උදාහරණයක්:
import React, { useRef } from 'react';
function UncontrolledForm() {
const nameInputRef = useRef(null);
const handleSubmit = (event) => {
event.preventDefault();
alert(`User Name: ${nameInputRef.current.value}`);
};
return (
<form onSubmit={handleSubmit}>
<label>නම:</label>
<input type="text" ref={nameInputRef} />
<button type="submit">Submit</button>
</form>
);
}
export default UncontrolledForm;කවදාද පාවිච්චි කරන්නේ?
- Simple Forms: ඉතාම සරල Forms වලදී.
- File Inputs:
<input type="file" />වගේ Components වලvalueඑක Programmatically set කරන්න බැරි නිසා. - Third-party DOM Libraries: React නොවන JavaScript Libraries එක්ක Integrate කරනකොට.
නමුත්, බොහෝ විට Controlled Components පාවිච්චි කරන්න කියලා තමයි React Recommend කරන්නේ. මොකද Controlled Components මගින් Form Data, State එකත් එක්ක Sync වෙලා තියෙන නිසා, Debug කරන්න, Validate කරන්න, සහ Data Flow එක Manage කරන්න පහසුයි.
5. හොඳම ක්රම සහ පොදු ගැටළු (Best Practices & Common Troubleshooting)
හොඳම ක්රම (Best Practices)
- හැමවිටම Controlled Components පාවිච්චි කරන්න: Predictable Behavior සහ පහසු Data Management නිසා මේවා තමයි හොඳම විකල්පය.
- Lift State Up: Form එකේ Data එක Components කිහිපයකට අවශ්ය නම්, Parent Component එකක State එක තියාගෙන
propsහරහා Data එක Share කරන්න. - Validation Logic වෙන් කරන්න: Validation Logic එක වෙනම Function එකක් විදිහට හරි, Custom Hook එකක් විදිහට හරි තියාගන්න.
- Third-Party Libraries: Form Handling Libraries (e.g., Formik, React Hook Form, Yup for validation) පාවිච්චි කරන්න පුළුවන්. මේවා Form handling process එක තවත් පහසු කරනවා.
පොදු ගැටළු සහ විසඳුම් (Common Troubleshooting)
- Input එකට Type කරද්දී Update වෙන්නේ නැහැ! (Input Not Updating)
- ගැටළුව:
inputඑකේvaluepropඑකටstateඑකක් දීලා, ඒත්onChangeevent handlerඑක දාලා නැත්තම්, නැත්තම්onChangeඑකෙන්stateඑක Update කරන්නේ නැත්නම්inputඑකට Type කරන්න බැරි වෙනවා. මොකදvalueඑක හැමවෙලාවෙමstateඑකෙන් එන නිසා. - විසඳුම:
onChangepropඑක අනිවාර්යයෙන් දාලා, ඒක ඇතුළතevent.target.valueඑකෙන්stateඑක Update කරන්න.
- ගැටළුව:
- State Updates ක්ෂණිකව 반영 වෙන්නේ නැහැ! (State Updates Not Reflecting Immediately)
- ගැටළුව:
setStateFunction එක asynchronous නිසා, සමහර වෙලාවටsetStateCall කරපු ගමන්ම ඊළඟ Line එකේදී අලුත්state valueඑක බලාපොරොත්තු වෙන්න බැහැ. - විසඳුම:
stateඑක Update වුනාට පස්සේ මොනවා හරි කරන්න ඕනි නම්,useEffectHook එක පාවිච්චි කරන්න පුළුවන්.
- ගැටළුව:
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
// මෙතනදී count එකේ අලුත් value එක ලැබෙන්නේ නැහැ, කලින් value එක තමයි තියෙන්නේ.
console.log(count); // Output කරන්නේ update වීමට පෙර තිබූ count අගයයි.
};
// count state එක වෙනස් වෙනකොට මේ effect එක run වෙනවා.
useEffect(() => {
console.log('Count updated to:', count);
}, [count]);// වැරදි
<input type="text" value={name} />
// නිවැරදි
<input type="text" value={name} onChange={(e) => setName(e.target.value)} />අවසන් වචනය (Conclusion)
React Forms සහ Controlled Components කියන්නේ React Development වලදී අත්යාවශ්යම Concept එකක්. අද අපි මේ Guide එකෙන් Forms වල මූලික කරුණු, Controlled Components කියන්නේ මොකක්ද, ඒවා කොහොමද පාවිච්චි කරන්නේ, වගේම Input Validation එකක් කොහොමද කරන්නේ කියලත් ඉගෙන ගත්තා. අපි හදපු Registration Form එක ඔයාට හොඳ ආරම්භයක් වෙයි කියලා මම හිතනවා.
මේ Concept එක හොඳට තේරුම් ගන්න නම්, අනිවාර්යයෙන්ම Code එක Try කරලා බලන්න. ඔයාගේම Form එකක් හදලා විවිධ Validation Rules එකතු කරලා බලන්න. මොනවා හරි ප්රශ්න තියෙනවා නම්, පහලින් Comment එකක් දාන්න. අපි ඒ ගැන කතා කරමු! ඔයාගේ React Journey එකට සුභ පැතුම්!