Các câu hỏi phỏng vấn về React – phần 2

9 min read

Hôm nay chúng ta sẽ tiếp tục với các câu hỏi phỏng vấn về kiến thức cơ bản trong React phần 2. Nếu các bạn chưa xem phần 1 thì có thể xem lại tại đây.

Sự khác biệt giữa xử lý sự kiện(event handling) HTML và React là gì?

Khi xử lý sự kiện trên thẻ HTML và React thì chúng ta sẽ có một số khác biệt chính dưới đây:

  • Trong HTML, tên sự kiện thường được viết bằng chữ thường(lowercase) như một quy ước. Trong khi đó ở React thì chúng ta lại phải tuân theo quy ước CamelCase.
//HTML onclick event
<button onclick="activateUser()"></button>

//React onClick event
<button onClick={activateUser} />
  • Trong HTML, bạn có thể return false để ngăn chặn hình vi mặc định(default behavior) trong một function. Trong khi đó ở React thì bạn phải gọi hàm preventDefault một cách rõ ràng.
//HTML
<a
  href="#"
  onclick='console.log("The link was clicked."); return false;'
/>

//React
function handleClick(event) {
  event.preventDefault();
  console.log("The link was clicked.");
}
  • Trong HTML, khi binding hàm thì bạn phải có đủ 2 dấu ngoặc tròn () phía sau tên hàm. Trong khi đó ở React thì bạn không cần thêm dấu ngoặc tròn () vào phía sau tên hàm, nhưng bạn cần sử dụng 2 dấu ngoặc {} thay vì 2 dấu nháy đôi ” như trong HTML. (bạn có thể xem ở ví dụ bên trên với hàm activateUser.

Truyền tham số cho hàm xử lý sự kiện hoặc hàm callback trong React như thế nào?

Bạn có thể sử dụng arrow function để bao quanh (wrap around) một hàm xử lý sự kiện và truyền tham số cho hàm đó.

<button onClick={() => this.handleClick(id)} />

Điều đó tương đương với việc gọi .bind

<button onClick={this.handleClick.bind(this, id)} />

Ngoài 2 cách tiếp cận trên thì bạn cũng có thể truyền tham số cho một hàm mà hàm đó được định nghĩa dưới dạng arrow function.

<button onClick={this.handleClick(id)} />;
handleClick = (id) => () => {
  console.log("Hello, your ticket number is", id);
};

Biểu thức nội tuyến(inline conditional expressions) trong React là gì?

Bạn có thể sử dụng câu lệnh if hoặc biểu thức 3 ngôi(ternary expressions) có sẵn trong javascript để hiển thị biểu thức có điều kiện. Ngoài cách tiếp cận này thì bạn cũng có thể nhúng bất kỳ biểu thức nào vào JSX bằng cách wrap chúng trong dấu ngoặc nhọn {}, sau đó sử dụng toán tử logic && của JS.

//Example 1:
return user !== null ? <div>{user.name}</div> : <div>User not found</div>;

//Example 2:
<h1>Hello!</h1>;
{
  messages.length > 0 && !isLogin ? (
    <h2>You have {messages.length} unread messages.</h2>
  ) : (
    <h2>You don't have unread messages.</h2>
  );
}

Thuộc tính “Key” là gì?

Key là một thuộc tính đặc biệt mà bạn nên đưa vào khi ánh xạ qua các mảng để hiển thị dữ liệu. Thuộc tính key giúp React xác định phần tử nào trong mảng đã được thay đổi, thêm hoặc xóa.

Key phải là duy nhất(unique), thông thường chúng ta sẽ sử dụng ID của phần tử trong dữ liệu nhận được để làm key. Nếu trên trang có các cùng khác nhau và hiển thị cùng một loại dữ liệu thì chúng ta nên thêm tiền tố(prefix) vào key để đảm bảo các key không trùng nhau.

const todoItems = todos.map((todo) => <li key={todo.id}>{todo.text}</li>);

Trong trường hợp mà dữ liệu của bạn không có trường ID dạng unique thì bạn có thể sử dụng chỉ số index của mảng để làm key. Lưu ý bạn nên sử dụng thêm tiền tố cho trường hợp này để giảm thiểu việc trùng key giữa các vùng khác nhau trên trang.

const todoItems = todos.map((todo, index) => (
  <li key={index}>{todo.text}</li>
));

Lưu ý:

  • Không nên sử dụng sử dụng index để làm key nếu thứ tự các phần tử trong mảng có thể thay đổi. Điều này có thể tác động tiêu cực đến hiệu suất và có thể gây ra vấn đề với trạng thái của component.
  • Nếu bạn trích xuất(extract) các phần tử dưới dạng các component riêng biệt thì phải áp dụng key trên các component thay vì thẻ bên trong component.
  • Sẽ có một message cảnh báo được hiển thị trên console của trình duyệt nếu như thuộc tính key không được set trong danh sách phần tử(list items).
  • Thuộc tính key chấp nhận chuỗi hoặc số và chuyển đổi nội bộ thành dạng chuỗi(string).
  • Không nên tạo key bằng cách sử dụng hàm Math.random(), bởi vì các key sẽ bị thay đổi giữa các lần render dẫn đến việc DOM được tạo lại mọi lúc. Điều này dẫn đến các vấn đề về performance.

Ref trong React là gì?

Ref (viết tắt của từ reference) là 1 hàm do React cung cấp để truy cập trực tiếp đến một phần tử DOM hoặc một thể hiện của một component con được tạo trong component. Chúng được sử dụng trong trường hợp chúng ta muốn thay đổi giá trị của một component con mà không cần sử dụng props và state.

Tạo Ref trong như thế nào? Truy cập Ref trong React như nào?

Chúng ta có thể tạo Ref bằng cách sử dụng hàm React.createRef() nếu bạn đang code theo class component hoặc sử dụng useRef nếu bạn đang code theo function component. Sau đó gắn vào phần tử thông qua thuộc tính ref.

//Class component
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}

//Function component
const MyComponent = () =>{
   const myRef = useRef();
   return(
      <div ref={myRef} />
   );
}

Ngoài ra bạn có thể tạo ref thông qua việc sử dụng hàm callback, tuy nhiên phương pháp này ít được sử dụng trong thời gian gần đây. Bạn có thể tham khảo ví dụ sau:

class SearchBar extends Component {
  constructor(props) {
    super(props);
    this.txtSearch = null;
    this.state = { term: "" };
    this.setInputSearchRef = (e) => {
      this.txtSearch = e;
    };
  }
  onInputChange(event) {
    this.setState({ term: this.txtSearch.value });
  }
  render() {
    return (
      <input
        value={this.state.term}
        onChange={this.onInputChange.bind(this)}
        ref={this.setInputSearchRef}
      />
    );
  }
}

Chúng ta có thể truy cập đến phần tử được set trong ref thông qua thuộc tính current;

const node = this.myRef.current;

Forward ref trong React là gì?

Ref forwarding là một tính năng cho phép một component lấy một ref mà chúng nhận được và truyền nó tới cho một component con.

const ButtonElement = React.forwardRef((props, ref) => (
  <button ref={ref} className="CustomButton">
    {props.children}
  </button>
));

// Create ref to the DOM button:
const ref = React.createRef();
<ButtonElement ref={ref}>{"Forward Ref"}</ButtonElement>;

Hàm forwardRef trả về một component mà bạn có thể render trong JSX.

Chúng ta thường sử dụng forwardRef trong các trường hợp:

Controlled component là gì?

Một component mà kiểm soát các input element bên trong một form trên các input của người dùng được gọi là Controlled Component, tức là mọi thay đổi của state sẽ có chức năng xử lý liên quan. Điều đó có nghĩa là dữ liệu được hiển thị luôn luôn đồng bộ với state của component.

Controlled component sẽ được triển khai bằng các bước sau:

  • Khởi tạo state bằng cách sử dụng các hook state trong function component hoặc bên trong constructor của class component.
  • Set giá trị của các element trong form theo các state tương ứng.
  • Tạo trình xử lý sự kiện (event handler) để xử lý các thay đổi đầu vào của người dùng (user input) thông qua hàm cập nhật của useState hoặc hàm setState từ class component.
  • Attach các event handler ở trên cho các thành phần của form thông qua các thuộc tính của element (onChange, onClick, …).

Ví dụ một form cập nhật thông tin username đơn giản như sau:

import React, { useState } from "react";

function UserProfile() {
  const [username, setUsername] = useState("");

  const handleChange = (e) => {
    setUsername(e.target.value);
  };

  return (
    <form>
      <label>
        Name:
        <input type="text" value={username} onChange={handleChange} />
      </label>
    </form>
  );
}

Uncontrolled component là gì?

Uncontrolled component là những component lưu trữ trạng thái riêng của chúng trong nội bộ và bạn truy vấn DOM bằng cách sử dụng ref để tìm giá trị hiện tại của nó khi bạn cần. Điều này giống với việc sử dụng các HTML element truyền thống.

Uncontrolled component sẽ được triển khai theo các bước sau:

  • Tạo một ref bằng cách sử dụng useRef trong function component hoặc React.createRef() trong class component.
  • Attach đối tượng ref đã khai báo bên trên cho element trên form.
  • Giá trị của element trên form có thể được truy cập trực tiếp thông ref trong event handler.

Ví dụ component UserProfile dưới đây, trường username được truy cập thông qua ref

import React, { useRef } from "react";

function UserProfile() {
  const usernameRef = useRef(null);

  const handleSubmit = (event) => {
    event.preventDefault();
    console.log("The submitted username is: " + usernameRef.current.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Username:
        <input type="text" ref={usernameRef} />
      </label>
      <button type="submit">Submit</button>
    </form>
  );
}

Trong hầu hết các trường hợp, bạn nên sử dụng Controlled component để triển khai các form. Trong một Controlled component dữ liệu của form được xử lý bởi React component.

Higher-Order Component (HOC) là gì?

Higher-Order Component (HOC) là một hàm nhận vào một component và trả về một component mới. Về cơ bản, đó là một mẫu bắt nguồn từ bản chất tổng hợp của React.

Chúng ta có thể gọi chúng là các pure component bởi vì chúng có thể chấp nhận bất kỳ component con nào được cung cấp động (dynamically) nhưng chúng sẽ không sửa đổi hoặc sao chép bất kỳ hành vi nào từ các component đầu vào của chúng.

HOC rất hữu ích để trừu tượng hóa (abstract) logic chung được nhiều thành phần sử dụng.

Dưới đây là 1 ví dụ đơn giản về việc sử dụng HOC để sử lý logic khi hover chuột lên 1 phần tử.

// Higher Order Component that Contians the logic
// to detect the hover.
function withHover(WrappedComponent) {
  return function (props) {
    const [isHovered, setHovered] = useState(false);

    function handleMouseEnter() {
      setHovered(true);
    }

    function handleMouseLeave() {
      setHovered(false);
    }

    return (
      <div onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
        <WrappedComponent {...props} isHovered={isHovered} />
      </div>
    );
  };
}

// Updated Text Component without the Hover Logic
const TextComponent = ({ text, isHovered }) => {
  return (
    <>
      <p style={{ backgroundColor: isHovered ? "blue" : "white" }}>{text}</p>
    </>
  );
};

// Updated Input Component without the Hover Logic
const InputComponent = ({ type, isHovered }) => {
  return (
    <input
      type={type}
      style={{ backgroundColor: isHovered ? "blue" : "white" }}
    />
  );
};

// Creating components that contain hover logic using
// Higher Order Component.
const TextComponentWithHover = withHover(TextComponent);
const InputComponentWithHover = withHover(InputComponent);

// Using the Components in our App
const App = () => {
  return (
    <div className="App">
      <TextComponentWithHover
        text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
        tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
        veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
        commodo consequat."
      />

      <InputComponentWithHover type="text" />
    </div>
  );
};

export default App;

Avatar photo

Leave a Reply

Your email address will not be published. Required fields are marked *