Sau khi đã có API, giờ là lúc chúng ta bắt đầu cài các màn hình phía client sử dụng ReactJS. Chúng ta sẽ cần cài đặt màn hình đăng ký, xác nhận, đăng nhập và trang chủ. Để bắt đầu một cách nhẹ nhàng, chúng ta hãy bắt đầu cài đặt màn hình đăng ký trước nhé.

Thiết kế màn hình

Chúng ta sẽ có thiết kế màn hình đăng ký đơn giản như sau:

Ở đây chúng ta có 4 ô nhập thông tin, 1 nút nhấn để gửi đăng ký và một đoạn câu hỏi kèm theo nút chuyển sang màn hình đăng nhập.

Mã nguồn giao diện ReactJS

Tương ứng với thiết kế giao diện chúng ta sẽ có mã nguồn của màn hình đăng ký sử dụng ReactJS như sau:

import React, { useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faUser, faEnvelope, faLock, faSignature } from '@fortawesome/free-solid-svg-icons';
import { Link } from 'react-router-dom';

interface RegisterFormState {
  username: string;
  password: string;
  email: string;
  displayName: string;
}

const Register: React.FC = () => {
  const [formState, setFormState] = useState<RegisterFormState>({
    username: '',
    password: '',
    email: '',
    displayName: '',
  });

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setFormState({
      ...formState,
      [name]: value,
    });
  };

  const handleSubmit = () => {};

  return (
    <div className="form-container">
      <form onSubmit={handleSubmit} className="register-form">
        <div className="input-group">
          <FontAwesomeIcon icon={faUser} className="icon" />
          <input
            type="text"
            name="username"
            placeholder="Username"
            value={formState.username}
            onChange={handleChange}
            required
          />
        </div>
        <div className="input-group">
          <FontAwesomeIcon icon={faSignature} className="icon" />
          <input
            type="text"
            name="displayName"
            placeholder="Display Name"
            value={formState.displayName}
            onChange={handleChange}
            required
          />
        </div>
        <div className="input-group">
          <FontAwesomeIcon icon={faEnvelope} className="icon" />
          <input
            type="email"
            name="email"
            placeholder="Email"
            value={formState.email}
            onChange={handleChange}
            required
          />
        </div>
        <div className="input-group">
          <FontAwesomeIcon icon={faLock} className="icon" />
          <input
            type="password"
            name="password"
            placeholder="Password"
            value={formState.password}
            onChange={handleChange}
            required
          />
        </div>
        <button type="submit">Register</button>
        <p className="login-link">
          Already have an account? <Link to="/login">Login</Link>
        </p>
      </form>
    </div>
  );
};

export default Register;

Ở đây chúng ta đang:

  1. Sử dụng React Hook, các trường dữ liệu của form được lưu vào một đối tượng nên tương đối là dễ hiểu và ngắn gọn.
  2. Sử dụng FontAwesomeIcon cho giao diện thêm phần sinh động.
  3. Sử dụng placeholder thay vì nhãn cho ngắn gọn.
    Kết quả chúng ta nhận được giao diện như sau:

Giao diện cực kỳ xấu và không thân thiện với người dùng, vậy nên chúng ta sẽ bổ sung mã nguồn css Register.css như sau:

.form-container {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: #f4f4f4;
  }
  
  .register-form {
    background-color: white;
    padding: 40px;
    border-radius: 10px;
    box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
    width: 400px;
  }
  
  .input-group {
    position: relative;
    margin-bottom: 20px;
  }
  
  .icon {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    color: #aaa;
  }
  
  input {
    width: 100%;
    padding: 10px 40px;
    box-sizing: border-box;
    font-size: 16px;
    border: 1px solid #ddd;
    border-radius: 5px;
    outline: none;
    transition: border-color 0.3s ease;
  }
  
  input:focus {
    border-color: #4CAF50;
  }
  
  button {
    width: 100%;
    padding: 12px;
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 5px;
    font-size: 16px;
    cursor: pointer;
    transition: background-color 0.3s ease;
  }
  
  button:hover {
    background-color: #45a049;
  }
  
  .login-link {
    margin-top: 20px;
    text-align: center;
  }
  
  .login-link a {
    color: #4CAF50;
    text-decoration: none;
    font-weight: bold;
    transition: color 0.3s ease;
  }
  
  .login-link a:hover {
    color: #45a049;
  }

  .register-link {
    margin-top: 20px;
    text-align: center;
  }
  
  .register-link a {
    color: #4CAF50;
    text-decoration: none;
    font-weight: bold;
    transition: color 0.3s ease;
  }
  
  .register-link a:hover {
    color: #45a049;
  }

Bổ sung import ‘./Register.css’; vào Register.tsx và trở lại trình duyệt chúng ta sẽ thấy giao diện sẽ đẹp hơn rất nhiều:

Cài đặt hàm gọi API

Trong mã nguồn giao diện ở trên, chúng ta vẫn để trống hàm:

const handleSubmit = () => {};

Bây giờ chúng ta có thể cài đặt hàm này để gọi API đăng ký người dùng với mã nguồn như sau:

const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [successMessage, setSuccessMessage] = useState<string | null>(null);

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    setErrorMessage(null);
    setSuccessMessage(null);

    try {
      const response = await axios.post(`${SERVER_URL}/users/register`, formState);
      setSuccessMessage('Registration successful!');
      console.log('Registration successful', response.data);
    } catch (error) { 
      if (axios.isAxiosError(error) && error.response) {
        setErrorMessage(error.response.data.message || 'Registration failed.');
      } else {
        setErrorMessage('An unknown error occurred.');
      }
      console.error('Registration failed', error);
    }
};

Ở đây chúng ta:

  1. Sử dụng axios để gọi API.
  2. SERVER_URL được khai báo trong tập tin configs/Config.ts: export const SERVER_URL = “http://localhost:3000”;
  3. Nếu thành công chúng ta sẽ hiển thị thông báo đăng ký thành công, ngược lại hiển thị thông báo đăng ký thất bại.

Mã nguồn đầy đủ

Ghép nối lại tất cả các mã nguồn lại với nhau, chúng ta sẽ có mã nguồn đầy đủ như sau:

import React, { useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faUser, faEnvelope, faLock, faSignature } from '@fortawesome/free-solid-svg-icons';
import axios from 'axios';
import './Register.css';
import { SERVER_URL } from './configs/Config';
import { Link } from 'react-router-dom';

interface RegisterFormState {
  username: string;
  password: string;
  email: string;
  displayName: string;
}

const Register: React.FC = () => {
  const [formState, setFormState] = useState<RegisterFormState>({
    username: '',
    password: '',
    email: '',
    displayName: '',
  });

  const [errorMessage, setErrorMessage] = useState<string | null>(null);
  const [successMessage, setSuccessMessage] = useState<string | null>(null);

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setFormState({
      ...formState,
      [name]: value,
    });
  };

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    setErrorMessage(null);
    setSuccessMessage(null);

    try {
      const response = await axios.post(`${SERVER_URL}/users/register`, formState);
      setSuccessMessage('Registration successful!');
      console.log('Registration successful', response.data);
    } catch (error) { 
      if (axios.isAxiosError(error) && error.response) {
        setErrorMessage(error.response.data.message || 'Registration failed.');
      } else {
        setErrorMessage('An unknown error occurred.');
      }
      console.error('Registration failed', error);
    }
  };

  return (
    <div className="form-container">
      <form onSubmit={handleSubmit} className="register-form">
        <div className="input-group">
          <FontAwesomeIcon icon={faUser} className="icon" />
          <input
            type="text"
            name="username"
            placeholder="Username"
            value={formState.username}
            onChange={handleChange}
            required
          />
        </div>
        <div className="input-group">
          <FontAwesomeIcon icon={faSignature} className="icon" />
          <input
            type="text"
            name="displayName"
            placeholder="Display Name"
            value={formState.displayName}
            onChange={handleChange}
            required
          />
        </div>
        <div className="input-group">
          <FontAwesomeIcon icon={faEnvelope} className="icon" />
          <input
            type="email"
            name="email"
            placeholder="Email"
            value={formState.email}
            onChange={handleChange}
            required
          />
        </div>
        <div className="input-group">
          <FontAwesomeIcon icon={faLock} className="icon" />
          <input
            type="password"
            name="password"
            placeholder="Password"
            value={formState.password}
            onChange={handleChange}
            required
          />
        </div>
        <button type="submit">Register</button>

        {/* Display success or error messages */}
        {errorMessage && <p className="error-message">{errorMessage}</p>}
        {successMessage && <p className="success-message">{successMessage}</p>}
        <p className="login-link">
          Already have an account? <Link to="/login">Login</Link>
        </p>
      </form>
    </div>
  );
};

export default Register;

Tiến hành đăng ký

Khởi động máy chủ NodeJS và quay trở lại trình duyệt chúng ta có thể điền thông tin đăng ký, nhấn nút đăng ký và chúng ta sẽ nhận được kết quả như sau:

Tổng kết

Như vậy chúng ta đã cùng nhau cài đặt màn hình đăng ký, trong bài tiếp theo chúng ta sẽ cài đặt màn hình xác thực, login và home nhé.


Cám ơn bạn đã quan tâm đến bài viết này. Để nhận được thêm các kiến thức bổ ích bạn có thể:

  1. Đọc các bài viết của TechMaster trên facebook: https://www.facebook.com/techmastervn
  2. Xem các video của TechMaster qua Youtube: https://www.youtube.com/@TechMasterVietnam nếu bạn thấy video/bài viết hay bạn có thể theo dõi kênh của TechMaster để nhận được thông báo về các video mới nhất nhé.
  3. Chat với techmaster qua Discord: https://discord.gg/yQjRTFXb7a