ReactJS: Cách xây dựng biểu mẫu (form) trong React


Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

Giới thiệu

Biểu mẫu là một thành phần quan trọng của các ứng dụng web React. Chúng cho phép người dùng trực tiếp nhập và gửi dữ liệu trong các thành phần khác nhau, từ màn hình đăng nhập đến trang thanh toán. Vì hầu hết các ứng dụng React là các ứng dụng trang đơn (SPA) hoặc các ứng dụng web tải một trang duy nhất qua đó dữ liệu mới được hiển thị động, bạn sẽ không gửi thông tin trực tiếp từ biểu mẫu đến máy chủ. Thay vào đó, bạn sẽ nắm bắt thông tin biểu mẫu ở phía máy khách và gửi hoặc hiển thị nó bằng cách sử dụng mã JavaScript bổ sung.

Các biểu mẫu React đưa ra một thách thức duy nhất vì bạn có thể cho phép trình duyệt xử lý hầu hết các phần tử biểu mẫu và thu thập dữ liệu thông qua các sự kiện thay đổi trong React hoặc bạn có thể sử dụng React để kiểm soát hoàn toàn phần tử bằng cách đặt và cập nhật trực tiếp giá trị đầu vào. Cách tiếp cận đầu tiên được gọi là thành phần không được kiểm soát vì React không thiết lập giá trị. Cách tiếp cận thứ hai được gọi là thành phần được kiểm soát vì React sẽ tích cực cập nhật đầu vào.

Trong hướng dẫn này, bạn sẽ xây dựng biểu mẫu bằng React và xử lý việc gửi biểu mẫu bằng một ứng dụng mẫu gửi yêu cầu mua táo. Bạn cũng sẽ tìm hiểu những ưu điểm và nhược điểm của các component được kiểm soát và không được kiểm soát. Cuối cùng, bạn sẽ tự động đặt các thuộc tính biểu mẫu để bật và tắt các trường tùy thuộc vào trạng thái biểu mẫu. Đến cuối hướng dẫn này, bạn sẽ có thể tạo nhiều biểu mẫu khác nhau bằng cách sử dụng input, checkbox, radiobox, danh sách chọn và hơn thế nữa.

Bước 1 - Tạo một dự án trống

Trong bước này, bạn sẽ tạo một dự án mới bằng Create React App. Sau đó, bạn sẽ xóa dự án mẫu và các tệp liên quan được cài đặt khi bạn khởi động dự án. Cuối cùng, bạn sẽ tạo một cấu trúc tệp đơn giản để tổ chức các component của mình. Điều này sẽ cung cấp cho bạn một cơ sở vững chắc để xây dựng ứng dụng mẫu của hướng dẫn này để tạo style trong bước tiếp theo.

Để bắt đầu, hãy thực hiện một dự án mới. Bạn mở terminal và chạy tập lệnh sau để cài đặt một dự án mới bằng cách sử dụng create-react-app:

npx create-react-app form-tutorial

Sau khi dự án kết thúc, hãy thay đổi vào thư mục:

cd form-tutorial

Khởi động dự án với lệnh:

npm start
Bạn sẽ nhận được một máy chủ cục bộ đang chạy. Nếu dự án không mở trong cửa sổ trình duyệt, bạn có thể mở nó bằng http://localhost:3000/. Nếu bạn đang chạy điều này từ một máy chủ từ xa, địa chỉ sẽ là .http://your_domain:3000

Trình duyệt của bạn sẽ tải với một ứng dụng React đơn giản được bao gồm như một phần của Create React App:

Dự án mẫu React

Bạn sẽ xây dựng một tập hợp các component tùy chỉnh hoàn toàn mới, vì vậy bạn sẽ cần bắt đầu bằng cách xóa một số mã soạn sẵn để bạn có thể có một dự án trống.

Để bắt đầu, hãy mở component src/App.js. Đây là component gốc được đưa vào trang. Tất cả các component sẽ bắt đầu từ đây. Bạn sửa lại file để trong đó chỉ còn chứa như sau:

import './App.css';

function App() {
  return <></>;
}

export default App;

Mở một terminal khác và thực hiện thao tác xóa file logo.svg:

rm src/logo.svg

Tạo thư mục components:

mkdir src/components

Tạo thư mục App:

mkdir src/components/App

Di chuyển các file App.* vào thư mục App:

mv src/App.* src/components/App

Mở file index.js và chỉnh sửa:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App/App';
import * as serviceWorker from './reportWebVitals';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

Lưu file lại và quay lại trang web ta được một trang web trống.

màn hình trống trong chrome

Bây giờ bạn đã hoàn thành dự án Tạo ứng dụng React mẫu, hãy tạo một cấu trúc tệp đơn giản. Điều này sẽ giúp bạn giữ cho các component của bạn cô lập và độc lập.

Tạo một thư mục được gọi components trong thư mục src, components sẽ là nơi chứa tất cả các component tùy chỉnh của bạn.

Bước 2 - Tạo biểu mẫu cơ bản với JSX

Trong bước này, bạn sẽ tạo một biểu mẫu trống với một phần tử duy nhất và một nút gửi bằng JSX. Bạn sẽ xử lý sự kiện gửi biểu mẫu và truyền dữ liệu sang một dịch vụ khác. Đến cuối bước này, bạn sẽ có một biểu mẫu cơ bản sẽ gửi dữ liệu đến một hàm không đồng bộ.

Để bắt đầu, hãy tạo và mở App.js ra:

Bạn sẽ xây dựng một biểu mẫu để mua táo. Tạo một <div> với className là <wrapper>. Sau đó, thêm một thẻ <h1> có nội dung "How About Them Apples" và một phần tử form trống bằng cách thêm mã được đánh dấu như sau:

import './App.css';

function App() {
  return (
    <div className="wrapper">
      <h1>How About Them Apples</h1>
      <form>
      </form>
    </div>
  )
}

export default App;

Tiếp theo, bên trong thẻ <form>, hãy thêm một phần tử <fieldset> và một phần tử <input> được bao ngoài bởi một thẻ <label>. Bằng cách bao ngoài phần tử <input> bằng một thẻ <label>, bạn đang hỗ trợ trình đọc màn hình bằng cách liên kết nhãn với input. Điều này sẽ tăng khả năng tiếp cận ứng dụng của bạn.

Cuối cùng, thêm một <button> submit ở cuối biểu mẫu:

import './App.css';

function App() {
  return(
    <div className="wrapper">
      <h1>How About Them Apples</h1>
      <form>
      <fieldset>
         <label>
           <p>Name</p>
           <input name="name" />
         </label>
       </fieldset>
       <button type="submit">Submit</button>
      </form>
    </div>
  )
}

export default App;

Lưu file lại.

Mở App.css để thiết lập style. Thêm padding vào .wrapper và margin vào fieldset để cung cấp một số khoảng cách giữa các phần tử:

.wrapper {
    padding: 5px 20px;
}

.wrapper fieldset {
    margin: 20px 0;
}

Lưu file lại và quay lại trang web, bạn refresh lại trang để được kết quả:

Biểu mẫu cơ bản với trường cho "tên" và nút gửi

Nếu bạn nhấp vào nút Submit, trang sẽ tải lại. Vì bạn đang xây dựng một ứng dụng trang đơn, bạn sẽ ngăn chặn hành vi tiêu chuẩn này đối với một nút có type="submit". Thay vào đó, bạn sẽ xử lý sự kiện submit bên trong component.

Mở App.js ra. Để xử lý sự kiện, bạn sẽ thêm một trình xử lý sự kiện vào phần tử <form> mà không phải <button>. Tạo một hàm được gọi là handleSubmit để lấy SyntheticEvent làm đối số. SyntheticEvent là một trình bao bọc xung quanh đối tượng Event chuẩn và chứa cùng một giao diện. Gọi .preventDefault để ngăn trang gửi biểu mẫu, sau đó kích hoạt alert để cho biết rằng biểu mẫu đã được gửi:

import './App.css';

function App() {
  const handleSubmit = event => {
    event.preventDefault();
    alert('You have submitted the form.')
  }

  return(
    <div className="wrapper">
      <h1>How About Them Apples</h1>
      <form onSubmit={handleSubmit}>
        <fieldset>
          <label>
            <p>Name</p>
            <input name="name" />
          </label>
        </fieldset>
        <button type="submit">Submit</button>
      </form>
    </div>
  )
}

export default App;

Lưu file lại và quay lại trang web, nếu bạn nhấp vào nút gửi, cảnh báo sẽ bật lên, nhưng cửa sổ sẽ không tải lại.

Cảnh báo gửi biểu mẫu

Trong nhiều ứng dụng React, bạn sẽ gửi dữ liệu đến một dịch vụ bên ngoài, chẳng hạn như API Web. Khi dịch vụ xử lý xong, bạn sẽ thường hiển thị thông báo thành công, chuyển hướng người dùng hoặc thực hiện cả hai.

Để mô phỏng một API, hãy thêm một hàm setTimeout trong hàm handleSubmit. Thao tác này sẽ tạo ra một hoạt động không đồng bộ đợi một khoảng thời gian nhất định trước khi hoàn thành, hoạt động này hoạt động tương tự như một yêu cầu dữ liệu bên ngoài. Sau đó, sử dụng Hook useState để tạo một biến submitting và một hàm setSubmitting. Gọi setSubmitting(true) khi dữ liệu được gửi và gọi setSubmitting(false) khi thời gian chờ được giải quyết:

import { useState } from 'react';
import './App.css';

function App() {
  const [submitting, setSubmitting] = useState(false);
  const handleSubmit = event => {
    event.preventDefault();
   setSubmitting(true);

   setTimeout(() => {
     setSubmitting(false);
   }, 3000)
 }

  return(
    <div className="wrapper">
      <h1>How About Them Apples</h1>
      {submitting &&
        <div>Submtting Form...</div>
      }
      <form onSubmit={handleSubmit}>
        <fieldset>
          <label>
            <p>Name</p>
            <input name="name" />
          </label>
        </fieldset>
        <button type="submit">Submit</button>
      </form>
    </div>
  )
}

export default App;

Ngoài ra, bạn sẽ thông báo cho người dùng biết form của họ được gửi bằng cách hiển thị một thông báo ngắn trong HTML và sẽ hiển thị khi submitting là true.

Lưu file lại và quay lại trang web ta được như sau:

Gửi biểu mẫu hiển thị thông báo trong 3 giây

Bây giờ bạn có một biểu mẫu cơ bản xử lý sự kiện gửi bên trong component React. Bạn đã kết nối nó với JSX của mình bằng cách sử dụng trình xử lý sự kiện onSubmit và bạn sử dụng Hook để hiển thị thông báo có điều kiện trong khi sự kiện handleSubmit đang chạy.

Trong bước tiếp theo, bạn sẽ thêm nhiều input hơn và lưu dữ liệu vào state khi người dùng điền dữ liệu vào biểu mẫu.

Bước 3 - Thu thập dữ liệu biểu mẫu bằng các component không được kiểm soát

Trong bước này, bạn sẽ thu thập dữ liệu biểu mẫu bằng cách sử dụng các component không được kiểm soát. Component không được kiểm soát là một component không có value được thiết lập bởi React. Thay vì đặt dữ liệu trên component, bạn sẽ kết nối với sự kiện onChange để thu thập thông tin đầu vào của người dùng. Khi bạn xây dựng các component, bạn sẽ tìm hiểu cách React xử lý các loại input khác nhau và cách tạo một hàm có thể sử dụng lại để thu thập dữ liệu biểu mẫu vào một đối tượng duy nhất.

Đến cuối bước này, bạn sẽ có thể tạo một biểu mẫu bằng cách sử dụng các phần tử biểu mẫu khác nhau, bao gồm cả danh sách thả xuống và hộp kiểm. Bạn cũng sẽ có thể thu thập, gửi và hiển thị dữ liệu biểu mẫu.

Lưu ý: Trong hầu hết các trường hợp, bạn sẽ sử dụng các component được kiểm soát cho ứng dụng React của mình. Nhưng bạn nên bắt đầu với các component không được kiểm soát để có thể tránh các lỗi nhỏ hoặc các vòng lặp ngẫu nhiên mà bạn có thể đưa vào khi đặt sai giá trị.

Hiện tại, bạn có một biểu mẫu có thể gửi thông tin, nhưng không có gì để gửi. Biểu mẫu có một phần tử <input> duy nhất , nhưng bạn không thu thập hoặc lưu trữ dữ liệu ở bất kỳ đâu trong component. Để có thể lưu trữ và xử lý dữ liệu khi người dùng gửi biểu mẫu, bạn cần tạo một cách để quản lý trạng thái. Sau đó, bạn sẽ cần kết nối với từng input bằng trình xử lý sự kiện.

Bên trong App.js, sử dụng Hook useReducer để tạo một đối tượng formData và một hàm setFormData. Đối với hàm reducer, kéo name và value từ đối tượng event.target và cập nhật state bằng cách mở rộng trạng thái hiện tại trong khi thêm name và value vào cuối. Điều này sẽ tạo ra một đối tượng state duy trì trạng thái hiện tại trong khi ghi đè các giá trị cụ thể khi chúng thay đổi:

import { useReducer, useState } from 'react';
import './App.css';

const formReducer = (state, event) => {
  return {
    ...state,
    [event.target.name]: event.target.value
  }
}

function App() {
  const [formData, setFormData] = useReducer(formReducer, {});
  const [submitting, setSubmitting] = useState(false);

  const handleSubmit = event => {
    event.preventDefault();
    setSubmitting(true);

    setTimeout(() => {
      setSubmitting(false);
    }, 3000)
  }

  return(
    <div className="wrapper">
      <h1>How About Them Apples</h1>
      {submitting &&
        <div>Submtting Form...</div>
      }
      <form onSubmit={handleSubmit}>
        <fieldset>
          <label>
            <p>Name</p>
            <input name="name" onChange={setFormData}/>
          </label>
        </fieldset>
        <button type="submit">Submit</button>
      </form>
    </div>
  )
}

export default App;

Sau khi tạo reducer, ta đã thêm setFormData vào trình xử lý sự kiện onChange trong input. Lưu file lại và quay lại trang web. Tuy nhiên, nếu bạn thử và nhập dữ liệu đầu vào, bạn có thể sẽ gặp lỗi dạng như sau:

Lỗi với SyntheticEvent

Vấn đề là SyntheticEvent được sử dụng lại và không thể được truyền cho một hàm không đồng bộ. Nói cách khác, bạn không thể truyền sự kiện trực tiếp. Để khắc phục điều này, bạn sẽ cần lấy dữ liệu cần thiết trước khi gọi hàm reducer.

Cập nhật hàm reducer để lấy một đối tượng có thuộc tính name và value. Sau đó, tạo một hàm được gọi là handleChange để kéo dữ liệu từ event.target và truyền đối tượng đến setFormData. Cuối cùng, cập nhật trình xử lý sự kiện onChange để sử dụng hàm mới:

import { useReducer, useState } from 'react';
import './App.css';

const formReducer = (state, event) => {
 return {
   ...state,
   [event.name]: event.value
 }
}

function App() {
  const [formData, setFormData] = useReducer(formReducer, {});
  const [submitting, setSubmitting] = useState(false);

  const handleSubmit = event => {
    event.preventDefault();
    setSubmitting(true);

    setTimeout(() => {
      setSubmitting(false);
    }, 3000);
  }

  const handleChange = event => {
    setFormData({
      name: event.target.name,
      value: event.target.value,
    });
  }

  return(
    <div className="wrapper">
      <h1>How About Them Apples</h1>
      {submitting &&
        <div>Submtting Form...</div>
      }
      <form onSubmit={handleSubmit}>
        <fieldset>
          <label>
            <p>Name</p>
            <input name="name" onChange={handleChange}/>
          </label>
        </fieldset>
        <button type="submit">Submit</button>
      </form>
    </div>
  )
}

export default App;

Lưu file lại và quay lại trang web và bạn có thể nhập dữ liệu vào input.

Bây giờ bạn đang thu thập state biểu mẫu, hãy cập nhật thông báo hiển thị người dùng để hiển thị dữ liệu trong phần tử <ul>.

Chuyển đổi dữ liệu thành một mảng bằng cách sử dụng Object.entries, sau đó ánh xạ dữ liệu chuyển đổi từng phần tử của mảng thành một phần tử <li> có tên và giá trị. Hãy chắc chắn sử dụng name làm prop key cho phần tử:

...
  return(
    <div className="wrapper">
      <h1>How About Them Apples</h1>
      {submitting &&
        <div>
          You are submitting the following:
          <ul>
            {Object.entries(formData).map(([name, value]) => (
              <li key={name}><strong>{name}</strong>: {value.toString()}</li>
            ))}
          </ul>
        </div>
      }
      <form onSubmit={handleSubmit}>
        <fieldset>
          <label>
            <p>Name</p>
            <input name="name" onChange={handleChange}/>
          </label>
        </fieldset>
        <button type="submit">Submit</button>
      </form>
    </div>
  )
}

export default App;

Lưu file lại và quay lại trang web và bạn có thể nhập và gửi dữ liệu:

Điền vào biểu mẫu và gửi

Bây giờ bạn đã có một biểu mẫu cơ bản, bạn có thể thêm nhiều phần tử hơn. Tạo một phần tử <fieldset> khác và thêm một phần tử <select> trong đó có đưa vào các giống táo khác nhau cho mỗi loại <option>, một <input> với type="number" và step="1" để có số lượng tăng lên 1 và một <input> có type="checkbox" cho tùy chọn gói quà.

Đối với mỗi phần tử, hãy thêm hàm handleChange vào trình xử lý sự kiện onChange:

...
  return(
    <div className="wrapper">
      <h1>How About Them Apples</h1>
      {submitting &&
        <div>
          You are submitting the following:
          <ul>
            {Object.entries(formData).map(([name, value]) => (
              <li key={name}><strong>{name}</strong>: {value.toString()}</li>
            ))}
          </ul>
        </div>
      }
      <form onSubmit={handleSubmit}>
        <fieldset>
          <label>
            <p>Name</p>
            <input name="name" onChange={handleChange}/>
          </label>
        </fieldset>
        <fieldset>
         <label>
           <p>Apples</p>
           <select name="apple" onChange={handleChange}>
               <option value="">--Please choose an option--</option>
               <option value="fuji">Fuji</option>
               <option value="jonathan">Jonathan</option>
               <option value="honey-crisp">Honey Crisp</option>
           </select>
         </label>
         <label>
           <p>Count</p>
           <input type="number" name="count" onChange={handleChange} step="1" />
         </label>
         <label>
           <p>Gift Wrap</p>
           <input type="checkbox" name="gift-wrap" onChange={handleChange} />
         </label>
       </fieldset>
        <button type="submit">Submit</button>
      </form>
    </div>
  )
}

export default App;

Lưu file lại và quay lại trang web bạn sẽ có thể nhập và chọn được nhiều loại dữ liệu khác nhau:

Biểu mẫu với tất cả các loại đầu vào

Có một trường hợp đặc biệt ở đây cần xem xét. Hộp kiểm value dành cho gói quà sẽ luôn là "on", bất kể mục đó có được chọn hay không. Thay vì sử dụng sự kiện value, bạn sẽ cần sử dụng thuộc tính checked.

Cập nhật hàm handleChange để xem event.target.type có checkbox không. Nếu có thì truyền thuộc tính event.target.checked làm value thay vì event.target.value:

import { useReducer, useState } from 'react';
import './App.css';

...

function App() {
  const [formData, setFormData] = useReducer(formReducer, {});
  const [submitting, setSubmitting] = useState(false);

  const handleSubmit = event => {
    event.preventDefault();
    setSubmitting(true);

    setTimeout(() => {
      setSubmitting(false);
    }, 3000);
  }

  const handleChange = event => {
   const isCheckbox = event.target.type === 'checkbox';
   setFormData({
     name: event.target.name,
     value: isCheckbox ? event.target.checked : event.target.value,
   })
 }
...

Trong đoạn code trên bạn đã sử dụng toán tử ba ngôi ? để tạo câu lệnh điều kiện.

Lưu file lại và quay lại trang web, hãy điền vào biểu mẫu và nhấp vào gửi. Bạn sẽ thấy rằng cảnh báo khớp với dữ liệu trong biểu mẫu:

Các phần tử biểu mẫu gửi dữ liệu chính xác

Như vậy trong bước này, bạn đã học cách tạo các thành phần biểu mẫu không kiểm soát. Bạn đã lưu dữ liệu biểu mẫu vào một state bằng cách sử dụng Hook useReducer và sử dụng lại dữ liệu đó trong các thành phần khác nhau. Bạn cũng đã thêm các loại thành phần biểu mẫu khác nhau và điều chỉnh hàm để lưu dữ liệu chính xác tùy thuộc vào loại phần tử.

Trong bước tiếp theo, bạn sẽ chuyển đổi các thành phần thành các thành phần được kiểm soát bằng cách đặt động giá trị thành phần.

Bước 4 - Cập nhật dữ liệu biểu mẫu bằng các thành phần được kiểm soát

Trong bước này, bạn sẽ tự động thiết lập và cập nhật dữ liệu bằng các thành phần được kiểm soát. Bạn sẽ thêm một prop value vào mỗi thành phần để thiết lập hoặc cập nhật dữ liệu biểu mẫu. Bạn cũng sẽ đặt lại dữ liệu biểu mẫu khi gửi.

Đến cuối bước này, bạn sẽ có thể kiểm soát động dữ liệu biểu mẫu bằng cách sử dụng state và prop React.

Với các thành phần không được kiểm soát, bạn không phải lo lắng về việc đồng bộ hóa dữ liệu. Ứng dụng của bạn sẽ luôn tuân theo những thay đổi gần đây nhất. Nhưng có nhiều trường hợp bạn sẽ cần cả đọc từ và ghi vào một thành phần input. Để làm điều này, bạn sẽ cần giá trị của thành phần là động.

Ở bước trước, bạn đã gửi một biểu mẫu. Nhưng sau khi gửi biểu mẫu thành công, biểu mẫu vẫn chứa dữ liệu cũ. Để xóa dữ liệu khỏi mỗi input, bạn sẽ cần thay đổi các thành phần từ các thành phần không được kiểm soát thành các thành phần được kiểm soát.

Một thành phần được kiểm soát tương tự như một thành phần không được kiểm soát, nhưng React cập nhật phần prop value. Nhược điểm là nếu bạn không cẩn thận và không cập nhật value đúng cách thì thành phần sẽ bị hỏng và dường như sẽ không cập nhật.

Trong biểu mẫu này, bạn đã lưu trữ dữ liệu, vì vậy để chuyển đổi các thành phần, bạn sẽ cập nhật phần prop value với dữ liệu từ state formData. Tuy nhiên, có một vấn đề: value không thể được undefined. Nếu giá trị của bạn là undefined, bạn sẽ nhận được lỗi trong console.

Vì state ban đầu của bạn là một đối tượng trống, bạn sẽ cần đặt giá trị thành giá trị từ formData hoặc giá trị mặc định, chẳng hạn như một chuỗi trống. Ví dụ: giá trị cho tên sẽ là formData.name || '':

...
  return(
    <div className="wrapper">
      <h1>How About Them Apples</h1>
      {submitting &&
        <div>
          You are submitting the following:
          <ul>
            {Object.entries(formData).map(([name, value]) => (
              <li key={name}><strong>{name}</strong>: {value.toString()}</li>
            ))}
          </ul>
        </div>
      }
      <form onSubmit={handleSubmit}>
        <fieldset>
          <label>
            <p>Name</p>
            <input name="name" onChange={handleChange} value={formData.name || ''}/>
          </label>
        </fieldset>
        <fieldset>
          <label>
            <p>Apples</p>
            <select name="apple" onChange={handleChange} value={formData.apple || ''}>
                <option value="">--Please choose an option--</option>
                <option value="fuji">Fuji</option>
                <option value="jonathan">Jonathan</option>
                <option value="honey-crisp">Honey Crisp</option>
            </select>
          </label>
          <label>
            <p>Count</p>
            <input type="number" name="count" onChange={handleChange} step="1" value={formData.count || ''}/>
          </label>
          <label>
            <p>Gift Wrap</p>
            <input type="checkbox" name="gift-wrap" onChange={handleChange} checked={formData['gift-wrap'] || false}/>
          </label>
        </fieldset>
        <button type="submit">Submit</button>
      </form>
    </div>
  )
}

export default App;

Như ở phần trên, hộp kiểm có một chút khác biệt. Thay vì đặt giá trị, bạn cần đặt thuộc tính checked. Nếu thuộc tính là true thì trình duyệt sẽ hiển thị hộp như được chọn. Đặt thuộc tính checked ban đầu thành false với formData['gift-wrap'] || false.

Nếu bạn muốn điền trước biểu mẫu, hãy thêm một số dữ liệu mặc định vào state formData. Đặt giá trị mặc định cho giá trị count bằng cách đặt giá trị formState mặc định là { count: 100 }. Bạn cũng có thể đặt các giá trị mặc định trong đối tượng ban đầu, nhưng bạn cần lọc ra các giá trị sai trước khi hiển thị thông tin biểu mẫu:

...

function App() {
  const [formData, setFormData] = useReducer(formReducer, {
   count: 100
 });
  const [submitting, setSubmitting] = useState(false);
...

Lưu file lại và quay lại trang web, bạn sẽ thấy input với dữ liệu mặc định:

Biểu mẫu có số lượng mặc định

Bây giờ bạn đã có các thành phần đang hoạt động, bạn có thể xóa dữ liệu khi gửi. Để làm như vậy, hãy thêm một điều kiện mới trong formReducer. Nếu event.reset là true, hãy trả về một đối tượng với các giá trị trống cho mỗi phần tử biểu mẫu. Đảm bảo thêm một giá trị cho mỗi input. Nếu bạn trả về một đối tượng trống hoặc một đối tượng không đầy đủ, các thành phần sẽ không cập nhật vì giá trị là undefined.

Sau khi bạn thêm điều kiện sự kiện mới vào formReducer, hãy cập nhật hàm submit của bạn để đặt lại trạng thái khi hàm giải quyết:

import { useReducer, useState } from 'react';
import './App.css';

const formReducer = (state, event) => {
  if(event.reset) {
    return {
      apple: '',
      count: 0,
      name: '',
      'gift-wrap': false,
    }
  }
  return {
    ...state,
    [event.name]: event.value
  }
}

function App() {
  const [formData, setFormData] = useReducer(formReducer, {
    count: 100
  });
  const [submitting, setSubmitting] = useState(false);

  const handleSubmit = event => {
    event.preventDefault();
    setSubmitting(true);

    setTimeout(() => {
      setSubmitting(false);
      setFormData({
       reset: true
      })
    }, 3000);
  }

...

Lưu file lại và quay lại trang web, bạn sẽ thấy form sẽ được clear sau khi gửi.

Lưu biểu mẫu và sau đó xóa dữ liệu

Trong bước này, bạn đã chuyển đổi các thành phần không được kiểm soát của mình thành các thành phần được kiểm soát bằng cách đặt động value hoặc các thuộc tính checked. Bạn cũng đã học cách nạp lại dữ liệu bằng cách đặt state mặc định và cách xóa dữ liệu bằng cách cập nhật form reducer để trả về giá trị mặc định.

Trong bước tiếp theo này, bạn sẽ đặt động các thuộc tính thành phần của biểu mẫu và vô hiệu hóa biểu mẫu trong khi nó đang gửi.

Bước 5 - Cập nhật động các thuộc tính biểu mẫu

Trong bước này, bạn sẽ cập nhật động các thuộc tính của phần tử biểu mẫu. Bạn sẽ đặt các thuộc tính dựa trên các lựa chọn trước đó và vô hiệu hóa biểu mẫu của mình trong quá trình gửi để ngăn chặn nhiều lần gửi ngẫu nhiên.

Hiện tại, mỗi thành phần đang là tĩnh. Chúng không thay đổi khi biểu mẫu thay đổi. Trong hầu hết các ứng dụng, biểu mẫu là động. Các trường sẽ thay đổi dựa trên dữ liệu trước đó. Chúng sẽ xác thực và hiển thị lỗi. Chúng có thể biến mất hoặc mở rộng khi bạn điền vào các thành phần khác.

Giống như hầu hết các component React, bạn có thể đặt động các thuộc tính và thuộc tính trên các thành phần và chúng sẽ hiển thị lại khi dữ liệu thay đổi.

Thử đặt một input là disabled cho đến khi một input khác đáp ứng một điều kiện. Cập nhật hộp kiểm Gift Wrap thành disabled trừ khi người dùng chọn tùy chọn fuji.

Bên trong App.js, bạn thêm thuộc tính disabled vào checkbox. Thuộc tính sẽ thành true nếu formData.apple là fuji:

...
        <fieldset>
          <label>
            <p>Apples</p>
            <select name="apple" onChange={handleChange} value={formData.apple || ''}>
                <option value="">--Please choose an option--</option>
                <option value="fuji">Fuji</option>
                <option value="jonathan">Jonathan</option>
                <option value="honey-crisp">Honey Crisp</option>
            </select>
          </label>
          <label>
            <p>Count</p>
            <input type="number" name="count" onChange={handleChange} step="1" value={formData.count || ''}/>
          </label>
          <label>
            <p>Gift Wrap</p>
            <input
             checked={formData['gift-wrap'] || false}
             disabled={formData.apple !== 'fuji'}
             name="gift-wrap"
             onChange={handleChange}
             type="checkbox"
            />
          </label>
        </fieldset>
        <button type="submit">Submit</button>
      </form>
    </div>
  )
}

export default App;

Lưu file lại và quay lại trang web, bạn sẽ thấy checkbox sẽ bị disabled theo mặc định:

Gói quà bị vô hiệu hóa

Nếu bạn chọn loại táo Fuji thì checkbox lại enable (được bật):

Gói quà được bật

Ngoài việc thay đổi thuộc tính trên các thành phần riêng lẻ, bạn có thể sửa đổi toàn bộ nhóm thành phần bằng cách cập nhật thành phần fieldset.

Ví dụ: bạn có thể vô hiệu hóa form trong khi form đang được gửi. Điều này sẽ ngăn việc submit nhiều lần và ngăn người dùng thay đổi các trường trước khi hàm handleSubmit xử lý xong hoàn toàn.

Thêm disabled={submitting} vào từng phần tử <fieldset> và cả phần tử <button> nữa:

...
      <form onSubmit={handleSubmit}>
        <fieldset disabled={submitting}>
          <label>
            <p>Name</p>
            <input name="name" onChange={handleChange} value={formData.name || ''}/>
          </label>
        </fieldset>
        <fieldset disabled={submitting}>
          <label>
            <p>Apples</p>
            <select name="apple" onChange={handleChange} value={formData.apple || ''}>
                <option value="">--Please choose an option--</option>
                <option value="fuji">Fuji</option>
                <option value="jonathan">Jonathan</option>
                <option value="honey-crisp">Honey Crisp</option>
            </select>
          </label>
          <label>
            <p>Count</p>
            <input type="number" name="count" onChange={handleChange} step="1" value={formData.count || ''}/>
          </label>
          <label>
            <p>Gift Wrap</p>
            <input
              checked={formData['gift-wrap'] || false}
              disabled={formData.apple !== 'fuji'}
              name="gift-wrap"
              onChange={handleChange}
              type="checkbox"
            />
          </label>
        </fieldset>
        <button type="submit" disabled={submitting}>Submit</button>
      </form>
    </div>
  )
}

export default App;

Lưu file lại và quay lại trang web, khi bạn gửi biểu mẫu thì các trường sẽ bị vô hiệu hóa cho đến khi hàm submit giải quyết xong hoàn toàn:

Tắt các thành phần biểu mẫu khi gửi

Bạn có thể cập nhật bất kỳ thuộc tính nào trên một thành phần input. Điều này rất hữu ích nếu bạn cần thay đổi input maxvalue chẳng hạn hoặc nếu bạn cần thêm thuộc tính pattern động để xác thực.

Như vậy trong bước này, bạn đặt động các thuộc tính trên các thành phần biểu mẫu. Bạn đã thêm một thuộc tính để bật hoặc tắt động một thành phần dựa trên đầu vào từ một thành phần khác và bạn đã vô hiệu hóa toàn bộ các phần bằng cách vô hiệu hóa các <fieldset>.

Phần kết luận

Biểu mẫu là chìa khóa cho các ứng dụng web phong phú. Trong React, bạn có các tùy chọn khác nhau để kết nối và kiểm soát các biểu mẫu và phần tử. Giống như các thành phần khác, bạn có thể cập nhật động các thuộc tính bao gồm các phần tử input với value. Các thành phần không được kiểm soát là tốt nhất để đơn giản hóa, nhưng có thể không phù hợp với các tình huống khi một thành phần cần được xóa hoặc điền trước dữ liệu. Các thành phần được kiểm soát cung cấp cho bạn nhiều cơ hội hơn để cập nhật dữ liệu, nhưng việc có thể thêm một mức độ trừu tượng khác có thể gây ra lỗi hoặc kết xuất không chủ ý.

Bất kể cách tiếp cận của bạn là gì, React cung cấp cho bạn khả năng tự động cập nhật và điều chỉnh các biểu mẫu của bạn cho phù hợp với nhu cầu của ứng dụng và người dùng của bạn.

» Tiếp: Cách xử lý khi tải dữ liệu không đồng bộ (async), tải chậm (lazy loading) và phân tách mã bằng React
« Trước: Cách xử lý sự kiện DOM và Window bằng React
Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!