Thứ năm, 12/12/2019 | 00:00 GMT+7

Quản lý trạng thái biểu mẫu trong phản ứng với biểu mẫu Redux

redux-form là một cách tốt để quản lý các biểu mẫu được cung cấp bởi Redux . Nó là một thành phần có thứ tự cao hơn (HOC) sử dụng react-redux đảm bảo các biểu mẫu HTML trong React sử dụng Redux để lưu trữ tất cả trạng thái của nó.

redux-form có các thành phần sau để giúp bạn xây dựng các ứng dụng của bạn :

  • formReducer() : Đây là một hàm cho biết cách cập nhật Redux store dựa trên những thay đổi đến từ ứng dụng; những thay đổi đó được mô tả bằng các hành động Redux. formReducer phải được gắn trên trạng thái Redux tại form .

  • reduxForm() : Hàm reduxForm() là một thành phần bậc cao nhận một đối tượng cấu hình và nó luôn trả về một hàm mới. Nó được sử dụng để bao bọc thành phần biểu mẫu và liên kết tương tác của user với các hành động điều phối Redux.

  • Thành phần <Field/> : Một thành phần nằm bên trong thành phần biểu mẫu được bao bọc của bạn. Nó phục vụ như một cách để kết nối các phần tử đầu vào trong một biểu mẫu với redux-form logic . Nói cách khác, đó là cách ta lấy thông tin đầu vào từ những gì user nhập.

Bạn có thể đọc thêm về API redux-form trong tài liệu của nó.

Trong hướng dẫn này, bạn sẽ sử dụng redux-form để xây dựng một biểu mẫu có xác thực và kết nối nó với cửa hàng Redux.

Yêu cầu

Để hoàn thành hướng dẫn này, bạn cần :

Bước 1 - Tạo dự án

Ta sẽ xây dựng một ứng dụng React với gói tạo ứng dụng . create-react-app cho phép bạn tạo các ứng dụng React mà không cần cấu hình bản dựng. Bạn có thể sử dụng create-react-app bằng cách chạy lệnh terminal sau đó. Nó tự động tạo một ứng dụng React cho bạn trong một folder có tiêu đề contact-redux .

  • npx create-react-app contact-redux

Điều quan trọng cần lưu ý là npx chỉ hoạt động với các version npm 5.2 trở lên. Nếu bạn có version thấp hơn version đó và vẫn muốn sử dụng create-react-app trên máy tính của bạn . Chạy các lệnh terminal bên dưới để cài đặt create-react-app và khởi động ứng dụng React.

  • npm install -g create-react-app
  • create-react-app contact-redux

Điều hướng đến folder và khởi động server phát triển đảm bảo mọi thứ hoạt động. Chạy lệnh sau để khởi động ứng dụng React mới được tạo ở chế độ phát triển:

  • npm start

Bạn sẽ thấy thông tin sau trong trình duyệt của bạn :

Ứng dụng React đang chạy trên trình duyệt

Bây giờ ta có một ứng dụng React đang chạy.

Thực thi lệnh sau để thêm các phần phụ thuộc mà bạn cần cho biểu mẫu.

  • npm install --save redux react-redux redux-form
  • redux - Một containers trạng thái và nó là yêu cầu để redux-form hoạt động.
  • react-redux - React Redux là liên kết React chính thức cho Redux và nó cũng là yêu cầu để redux-form hoạt động
  • redux-form - Gói được sử dụng cho hướng dẫn này.

Sau khi đã được cài đặt, bạn có thể làm việc trên biểu mẫu liên hệ.

Bước 2 - Tạo biểu mẫu

Ta sẽ thêm liên kết Bulma CDN vào index.html để thêm một số kiểu mặc định. Mở public/index.html và thêm dòng mã sau vào thẻ head :

public / index.html
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.min.css"> 

Ta sẽ thực hiện một số chỉnh sửa đối với file src/App.js ngay bây giờ. Mở file src/App.js và thêm dòng mã bên dưới vào đầu file .

src / App.js
import { reduxForm, Field } from 'redux-form'; 

Tiếp theo, đi tới hàm render() và sửa đổi nó bằng đoạn mã sau:

src / App.js
render() {     return (       <div className="App">         <header className="App-header">           <img src={logo} className="App-logo" alt="logo" />           <h1 className="App-title">Welcome to React x redux-form</h1>         </header>         <div className="container">           <p className="App-intro">             Contact Form           </p>           <SignInForm />         </div>       </div>     );   } 

Văn bản giới thiệu đã được thay đổi và quan trọng nhất là ta đã thêm thành phần <SignInForm /> mà ta sẽ tạo bên dưới. Nó sẽ là một thành phần đơn giản trả về biểu mẫu ta cần và nó sẽ được nối với thành phần redux-form . Trong cùng một file src/App.js , hãy nhập mã này bên dưới ngay trước khi khai báo class App extends Component .

src / App.js
let SignInForm = props => {   return <form className="form">     <div className="field">       <div className="control">         <label className="label">First Name</label>         <Field className="input" name="firstName" component="input" type="text" placeholder="First Name"/>       </div>     </div>      <div className="field">       <div className="control">         <label className="label">Last Name</label>         <Field className="input" name="lastName" component="input" type="text" placeholder="Last Name"/>       </div>     </div>      <div className="field">       <div className="control">         <label className="label">Email</label>         <Field className="input" name="email" component="input" type="email" placeholder="Email Address"/>       </div>     </div>      <div className="field">       <div className="control">         <label className="label">Proficiency</label>         <div className="select">           <Field className="input" name="proficiency" component="select">             <option />             <option value="beginner">Beginner Dev</option>             <option value="intermediate">Intermediate Dev</option>             <option value="expert">Expert Dev</option>           </Field>         </div>       </div>     </div>      <div className="field">       <div className="control">         <label className="label">Age</label>         <Field className="input" name="age" component="input" type="number" placeholder="Age"/>       </div>     </div>      <div className="field">       <div className="control">         <label className="checkbox">           <Field name="saveDetails" id="saveDetails" component="input" type="checkbox"/>           Save Details         </label>       </div>     </div>      <div className="field">       <div className="control">         <label className="label">Message</label>         <Field className="textarea" name="message" component="textarea" />       </div>     </div>      <div className="field">       <div className="control">         <button className="button is-link">Submit</button>       </div>     </div>    </form>; }; 

Trong mã này, ta cài đặt một biểu mẫu liên hệ tối thiểu, biểu mẫu này yêu cầu user cung cấp thông tin như Tên, Họ và Tuổi. Một chút thú vị trong biểu mẫu này là thành phần Field .

Thành phần Field đến từ gói redux-form và đó là cách ta viết trường input . type hỗ trợ cho biết loại đầu vào đó phải là, tức là đầu vào radio , đầu vào checkbox , đầu vào text hoặc đầu vào email . Thành component prop xác định loại trường đầu vào mà nó phải là, nó có thể là input , textarea hoặc thẻ selectname prop là thứ sẽ được sử dụng để xác định trạng thái của các trường trong cửa hàng redux mà ta sẽ tạo bên dưới.

Vì vậy, để sử dụng biểu mẫu được nối với biểu mẫu redux, ta cần có một số loại cửa hàng Redux đã được tạo và đó là những gì ta sẽ làm tiếp theo.

Bước 3 - Cài đặt Redux Store

Ta cần một cửa hàng Redux trong đó ta có thể kết nối thành phần biểu mẫu ( SignInForm ) mà ta đã tạo. Hãy bắt đầu bằng lệnh gói redux . Mở file src/index.js và thêm các dòng mã sau, trong đó về cơ bản ta đang nhập redux vào ứng dụng React.

src / index.js
import { createStore, combineReducers } from 'redux'; import { Provider } from 'react-redux'; import { reducer as formReducer } from 'redux-form'; 

Dòng mã đầu tiên nhập createStore và kết combineReducers . createStore giúp tạo một cửa hàng Redux chứa cây trạng thái hoàn chỉnh của ứng dụng của bạn và các combineReducers giúp quản lý tất cả các chức năng giảm thiểu của bạn thành một chức năng trợ giúp duy nhất mà sau đó có thể được chuyển vào createStore . Bạn có thể đọc thêm về các chức năng này trên trang tham chiếu API Redux.

Dòng mã thứ hai nhập Provider từ react-redux . Provider giúp chuyển trạng thái của cửa hàng cho tất cả các thành phần containers trong ứng dụng và ta sẽ trình bày cách hoạt động sau.

Dòng mã thứ ba nhập trình reducer dưới dạng formReducer và đó là những gì ta sẽ sử dụng để kết nối biểu mẫu của ta với cửa hàng Redux.

Tiếp theo, ta sẽ tạo cửa hàng Redux thực tế và đảm bảo nó có thể áp dụng cho tất cả các thành phần containers bằng cách sử dụng thành phần Provider . Chỉnh sửa file src/index.js với khối mã sau.

src / index.js
import React from 'react'; import ReactDOM from 'react-dom';  import { createStore, combineReducers } from 'redux'; import { Provider } from 'react-redux'; import { reducer as formReducer } from 'redux-form';  import './index.css'; import App from './App'; import registerServiceWorker from './registerServiceWorker';  const rootReducer = combineReducers({   form: formReducer, });  const store = createStore(rootReducer);  ReactDOM.render(   <Provider store={store}>     <App />   </Provider>,   document.getElementById('root') );  registerServiceWorker(); 

Trong khối mã ở trên, ta sử dụng hàm combineReducers để kết nối formReducer từ biểu mẫu đến cửa hàng Redux. Về cơ bản, nó được sử dụng để cập nhật bất kỳ trạng thái nào của ta để phản ứng lại các hành động, trong trường hợp này, là các thay đổi đối với biểu mẫu. Dòng mã tiếp theo được sử dụng để tạo cửa hàng bằng cách sử dụng createStore từ Redux.

Cửa hàng mới được tạo này sau đó được cung cấp cho tất cả các phần của ứng dụng với sự trợ giúp của Provider được bao bọc xung quanh thành phần App và nó cũng chấp nhận một cửa hàng hỗ trợ là store đã được tạo ở trên.

Hãy quay lại biểu mẫu và cuối cùng kết nối nó với cửa hàng.

## Bước 4 - Kết nối Biểu mẫu với biểu mẫu redux

Ta có thành phần biểu mẫu của bạn nhưng nó chưa được kết nối với redux-form . Hãy khắc phục điều đó. Nhập khối mã này bên dưới ngay trước khi class App extends Component và ngay sau khi khai báo thành phần trình bày SignInForm.

src / index.js
SignInForm = reduxForm({   form: 'signIn', })(SignInForm); 

Trong khối mã ở trên, SignInForm được tạo thành một biểu mẫu được kết nối với redux bằng cách sử dụng Thành phần thứ tự cao hơn của reduxForm . Điều này nghĩa là biểu mẫu của ta hiện đã được kết nối với cửa hàng.
Một điều cần lưu ý là form khóa cấu form , nó được sử dụng như một định danh và nó được sử dụng để cung cấp tên duy nhất cho thành phần biểu mẫu. Nếu chúng là nhiều biểu mẫu, thì bạn cần phải sử dụng các tên riêng biệt để quản lý tốt hơn các trạng thái khác nhau của chúng.

Điều tiếp theo ta phải làm là cấu hình những gì sẽ xảy ra khi ta nhấp vào nút Gửi. Trong một ứng dụng lý tưởng, bạn muốn gửi dữ liệu đến một API từ xa hoặc một số database nhưng với mục đích demo , ta sẽ đăng nhập dữ liệu biểu mẫu vào console của trình duyệt. Để làm điều đó, ta cần lấy dữ liệu biểu mẫu từ các đạo cụ và lưu trữ chúng ở đâu đó.

Bên trong thành phần SignInForm , hãy thêm dòng mã bên dưới ngay trên câu lệnh return .

src / index.js
    const { handleSubmit } = props;   return <form **onSubmit={handleSubmit}** className="form"> 

Các props trong biểu mẫu SignInForm bị hủy thành handleSubmit . Sau handleSubmit hàm handleSubmit sẽ được sử dụng trong biểu mẫu như một trình xử lý cho sự kiện onSubmit khi nút gửi được nhấp vào.

Cuối cùng, bên trong thành phần App trong file src/App.js , ta sẽ tạo một hàm ghi dữ liệu biểu mẫu vào console trình duyệt. Thêm khối mã bên dưới vào file ngay trước hàm render() .

src / App.js
  handleSignIn = values => {         console.log(values);     }; 

Sau đó, thêm hàm handleSignIn làm trình xử lý sự kiện cho thành phần SignInForm . redux-form sẽ tự động xác định rằng dữ liệu nhận được từ biểu mẫu, về cơ bản là thành phần SignInForm nên được ghi vào console nhờ vào hàm handleSubmit ở trên.

src / App.js
    <SignInForm onSubmit={this.handleSignIn} /> 

Đến đây bạn có thể khởi động ứng dụng bằng cách chạy lệnh npm start terminal. Điền vào biểu mẫu, nhấp vào gửi và bạn sẽ thấy các giá trị được ghi vào console .

Kết quả từ biểu mẫu hiển thị trong console

Bước 5 - Thêm xác thực

Xác thực rất quan trọng khi nói đến việc xây dựng biểu mẫu và tàu redux-form với một số tính năng xác thực và ta sẽ triển khai điều đó ngay bây giờ. Trong file src/App.js , nhập khối mã bên dưới.

src / App.js
const validate = val => {   const errors = {};   if (!val.firstName) {     console.log('First Name is required');     errors.firstName = 'Required';   }   if (!val.lastName) {     console.log('Last Name is required');     errors.lastName = 'Required';   }   if (!val.email) {     console.log('email is required');     errors.email = 'Required';   } else if (!/^.+@.+$/i.test(val.email)) {     console.log('email is invalid');     errors.email = 'Invalid email address';   }   if (!val.age) {     errors.age = 'Required'   } else if (isNaN(Number(val.age))) {     errors.age = 'Must be a number'   } else if (Number(val.age) < 18) {     errors.age = 'Sorry, you must be at least 18 years old'   }   return errors; }; 

Chức năng validate được sử dụng để kiểm tra các lỗi xác thực trong biểu mẫu. Tham số val sẽ được sử dụng để kiểm tra tính hợp lệ của các trường khác nhau. Đầu tiên ta kiểm tra xem đối tượng errors có trống không, đối tượng trống rõ ràng nghĩa là không có lỗi. Sau đó, ta sử dụng logic có điều kiện để kiểm tra xem một trường có trống không, nếu có thì bạn ném ra lỗi tương ứng. Trong khối mã ở trên, ta chỉ thực hiện xác thực cho firstName , lastName , emailage .
Trong điều kiện xác thực email , ta kiểm tra xem nó có trống không và cũng kiểm tra xem đó có phải là email hợp lệ hay không bằng cách sử dụng regex và trong điều kiện xác thực age , ta kiểm tra xem nó có trống không, một số và nếu user dưới 18 tuổi.

Tiếp theo, ta sẽ đăng ký chức năng xác thực của bạn vào redux-form để nó có thể bắt đầu sử dụng nó để thực hiện các bài kiểm tra xác thực. Thêm hàm validate vào Thành phần Thứ tự Cao hơn redux-form :

src / index.js
 SignInForm = reduxForm({   form: 'signIn',   validate, })(SignInForm); 

Bây giờ ta đã có sẵn chức năng xác thực và được đăng ký trong HOC redux-form , hãy xây dựng một thành phần có thể tái sử dụng hiển thị lỗi khi nào có bất kỳ lỗi nào và sử dụng thành phần mới tạo đó trong các biểu mẫu của ta .

src / index.js
  const renderField = ({ input, label, type, meta: { touched, error, warning } }) => (   <div>     <div className="control">       <label className="field">{label}</label>       <input className="input" {...input} placeholder={label} type={type}/>       {touched && ((error && <span>{error}</span>) || (warning && <span>{warning}</span>))}     </div>   </div> ) 

Thành phần renderField nhận các đạo cụ của đối tượng input , label , type đầu vào và meta là một redux-form . Dòng {touched && ((error && <span>{error}</span>) || (warning && <span>{warning}</span>))} nghĩa là thông báo lỗi sẽ hiển thị nếu có bất kỳ lỗi nào khi trường biểu mẫu đã được nhấp / tập trung vào. Ngoài ra, biểu mẫu sẽ không được gửi nếu có bất kỳ sai sót nào.

Bây giờ, nếu bạn kiểm tra biểu mẫu và cố gắng nhập bất kỳ đầu vào không hợp lệ nào hoặc bỏ qua các trường có kiểm tra xác thực, bạn sẽ có thông báo lỗi bên dưới biểu mẫu.

Dự án đã hoàn thành với các thông báo xác thực

Kết luận

Trong hướng dẫn này, bạn đã tạo một biểu mẫu với redux-form và kết nối nó với cửa hàng Redux. Bạn đã thêm xác thực đồng bộ vào biểu mẫu mà không cần trình xác thực giản đồ bên ngoài.

Bạn có thể đọc thêm về redux-form trên trang web chính thức và bạn có thể xem qua các ví dụ của chúng để khám phá thêm.

Bạn có thể tìm thấy mã hoàn chỉnh cho hướng dẫn này trên GitHub .


Tags:

Các tin liên quan