React Forms, Controlled Components, Validation | Sinhala Guide

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 එකෙන් වෙන්නේ:

  1. useState('') මගින් name කියන state variable එකක් හදාගන්නවා, මුලින් හිස් string එකක් විදිහට.
  2. <input> එකේ value={name} කියල දානවා, ඒ කියන්නේ input එකේ වත්මන් අගය හැමවෙලාවෙම name state එකේ තියෙන අගයයි.
  3. onChange={handleChange} මගින් කියන්නේ input එකට මොනවා හරි type කරාම handleChange function එක ක්‍රියාත්මක වෙන්න ඕනේ කියලා.
  4. handleChange function එක ඇතුලේ setName(event.target.value) මගින් input එකේ අලුත් අගය name state එකට දානවා.

මේ ක්‍රමයෙන් 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 handleChange Function එකක්: handleChange function එක ඇතුලේ 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 මගින් errors state එකට ඒ Errors ටික එකතු කරනවා.
  • Error Messages Display කිරීම: {errors.name && <p>{errors.name}</p>} වගේ Conditional Rendering පාවිච්චි කරලා Errors තියෙනවා නම් ඒ input එක යටින් Error Message එක පෙන්නනවා.
  • Form Submission Handling: <form> එකට onSubmit={handleSubmit} දාලා Form එක Submit කරනකොට handleSubmit function එක ක්‍රියාත්මක කරනවා. මේක ඇතුලේ 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 එකේ value prop එකට state එකක් දීලා, ඒත් onChange event handler එක දාලා නැත්තම්, නැත්තම් onChange එකෙන් state එක Update කරන්නේ නැත්නම් input එකට Type කරන්න බැරි වෙනවා. මොකද value එක හැමවෙලාවෙම state එකෙන් එන නිසා.
    • විසඳුම: onChange prop එක අනිවාර්යයෙන් දාලා, ඒක ඇතුළත event.target.value එකෙන් state එක Update කරන්න.
  • State Updates ක්ෂණිකව 반영 වෙන්නේ නැහැ! (State Updates Not Reflecting Immediately)
    • ගැටළුව: setState Function එක asynchronous නිසා, සමහර වෙලාවට setState Call කරපු ගමන්ම ඊළඟ Line එකේදී අලුත් state value එක බලාපොරොත්තු වෙන්න බැහැ.
    • විසඳුම: state එක Update වුනාට පස්සේ මොනවා හරි කරන්න ඕනි නම්, useEffect Hook එක පාවිච්චි කරන්න පුළුවන්.
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 එකට සුභ පැතුම්!