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

11 min read

React là gì?

React (còn được gọi là ReactJS hoặc React.js) là một thư viện FE javascript mã nguồn mở được sử dụng để xây dựng giao diện người dùng(UI), đặc biệt là cho các ứng dụng single-page. Nó được sử dụng để xử lý lớp View cho web hoặc ứng dụng di động(mobile app) dựa trên các component theo cách tiêp cận khai báo(declarative approach).

React được tạo ra bởi Jordan Walke, một kỹ sư phần mềm làm việc cho Facebook. React lần đầu tiên được triển khai trên News Feed của Facebook vào năm 2011 và trên Instagram vào năm 2012.

Các tính năng chính của React là gì?

  • React sử dụng cú pháp JSX(JavaScript XML), một cú pháp mở rộng của JS cho phép các developer viết mã HTML bên trong mã JS của họ.
  • React sử dụng DOM ảo(Virtual DOM) thay cho DOM thật(Real DOM) vì các thao tác trên DOM thật của trang sẽ rất tốn kém và ảnh hưởng hiệu suất(performance) của trang.
  • React tuân theo luồng dữ liệu một chiều(one-way data flow).
  • React sử dụng các component để xây dựng View, vì vậy nó có thể tái sử dụng và kết hợp giữa các component đã được khai báo để tạo nên các giao diện từ đơn giản đến phức tạp.
  • Hiện tại React cũng hỗ trợ server-side rendering(SSR) cho các ứng dụng web cần tối ưu hóa cho công cụ tìm kiếm(SEO – Search Engine Optimazations).

JSX là gì?

JSX là viết tắt của cụm từ JavaScript XML và nó là phần mở rộng cú pháp giống XML cho ECMAScript. Về cơ bản nó cung cấp cú pháp đặc biệt cho hàm React.createElement(type, props, …children), mang lại cho chúng ta khả năng biểu đạt của Javascript cùng với cú pháp mẫu giống như HTML.

Trong ví dụ bên dưới, văn bản trong thẻ <h1> được trả về dưới dạng hàm Javascript cho hàm render.

export default function App() {
  return (
      <h1 className="greeting">Hello, this is a JSX Code!</h1>
  );
}

Nếu bạn không sử dụng cú pháp JSX thì đoạn code bên trên sẽ được viết như sau:

import { createElement } from 'react';

export default function App() {
  return createElement(
    'h1',
    { className: 'greeting' },
    'Hello, this is a JSX Code!'
  );
}

Rõ ràng với việc sử dụng cú pháp JSX thì code của chúng ta trở nên dễ đọc hơn và dễ kiểm soát việc đóng/mở các thẻ HTML trong các giao diện có tính phức tạp. Nó là một bước xảy ra giữa hàm render được gọi và hiển thị của các phần tử lên màn hình. Toàn bộ quá trình này được gọi là reconciliation.

Virtual DOM là gì?

Virtual DOM (viết tắt là VDOM) là một khái niệm lập trình trong đó sự thể hiện của một DOM thật(real DOM) được lưu giữ trong bộ nhớ và được đồng bộ với DOM thật.

Cách tiếp cận này cho phép React biết bạn muốn giao diện người dùng (UI) ở trạng thái nào và nó đảm bảo DOM khớp với trạng thái đó.

Vì VDOM giống một mẫu hơn là một công nghệ cụ thể nên đôi khi người ta hiểu nó với nhiều nghĩa khác nhau. Trong React, thuật ngữ “virtual DOM” thường được liên kết với các phần tử React vì chúng là đối tượng đại diện cho giao diện người dùng.

Tuy nhiên, React cũng sử dụng các đối tượng bên trong (internal objects) được gọi là “fibers” để chứa thông tin bổ sung về cây component. Chúng cũng có thể được goi là một phần của quá trình triển khai “virtual DOM” trong React.

Virtual DOM hoạt động như nào?

Virtual DOM hoạt động theo ba bước đơn giản sau:

  • Bất cứ khi nào có dữ liệu cơ bản nào thay đổi, toàn bộ UI sẽ được re-render dưới dạng biểu diễn Virtual DOM.
  • Sau đó, sự khác biệt giữa biểu diễn (representation) DOM trước và biểu diễn DOM mới được tính toán.
  • Sau khi tính toán xong, DOM thật sẽ chỉ được cập nhật những thứ đã thực sự thay đổi.

Sự khác nhau giữa Shadow DOM và Virtual DOM là gì?

Shadow DOM là một công nghệ trình duyệt được thiết kế chủ yếu để xác định phạm vị các biến và CSS trong các web component. Virtual DOM là một khái niệm được triển khai bởi các thư viện bằng Javasript trên API trình duyệt.

React Fiber là gì?

Fiber là một công cụ điều chỉnh mới (new reconciliation engine) trong React 16. Mục tiêu chính của nó là cho phép tăng tính phù hợp cho các phần như animation, layout, cử chỉ, khả năng tạm dừng, hủy bỏ hoặc sử dụng lại công việc và chỉ định mức độ ưu tiên cho các loại cập nhật khác nhau.

Sự khác biệt giữa Element và Component trong React là gì?

Một Element là một đối tượng đơn giản mô tả những gì bạn muốn xuất hiện trên màn hình dưới dạng các DOM node hoặc các component khác. Các Element có thể chứa các Element khác trong các props của chúng. Một khi một element được tạo ra, nó không thể bị thay đổi(mutated).

Mã javascript của một React Element(không dùng JSX) sẽ như sau:

const element = React.createElement("div", { id: "login-btn" }, "Login");

và phần tử này có thể được đơn giản hóa bằng cách sử dụng JSX

<div id="login-btn">Login</div>

Hàm React.createElement() ở trên trả về một đối tượng như sau:

{
  type: 'div',
  props: {
    children: 'Login',
    id: 'login-btn'
  }
}

Cuối cùng, phần tử này được render trên DOM bằng hàm ReactDOM.render()

Trong khi đó Component có thể được khai báo theo nhiều cách khác nhau. Nó có thể làm một class với phương thức render hoặc nó có thể được định nghĩa như một hàm(function). Trong cả 2 trường hợp, nó nhận props làm đầu vào(input) và trả về cây JSX dưới dạng đầu ra(output).

//Class component
class Button extends React.Component {
  render() {
    return (
      <div id="login-btn" onClick={this.props.handleLogin}>
        Login
      </div>
    );
  }
}

//Function component
const Button = ({ handleLogin }) => (
  <div id={"login-btn"} onClick={handleLogin}>
    Login
  </div>
);

Khi nào nên sử dụng Class Component thay vì Function Component?

Sau khi bổ sung thêm Hook(từ phiên bản 16.8), React luôn khuyến nghị sử dụng Function Component thay vì Class Component. Bởi vì bạn có thể sử dụng state, các phương thức lifecycle và các tính tính năng khác có trong class component cũng có trong function component.

Nhưng có những lý do để sử dụng Class component thay vì Function component

  • Nếu bạn cần một chức năng React mà Function component chưa có, chẳng hạn như Error Boundaries.
  • Nếu bạn cần quản lý state hoặc sử dụng các lifecyle methods.
  • Trong các trường hợp cần có khả năng tương thích ngược(backward compatibility) hoặc cần tích hợp với mã cũ hơn.

Pure component là gì?

Pure component là component mà render cùng một output cho cùng một state và props. Trong function component, bạn có thể đạt được các pure component thông qua việc sử dụng hàm React.memo() để bọc component. Hàm này ngăn chặn việc render lại không cần thiết bằng cách so sánh các props trước đó và props mới bằng cách sử dụng so sánh nông(shallow comparison). Vì vậy, nó sẽ hữu ích cho việc tối ưu hóa hiệu suất.

Nhưng đồng thời, nó sẽ không so sánh trạng thái trước đó với trạng thái hiện tại vì chính function component sẽ ngăn chặn việc render không cần thiết theo mặc định khi bạn set lại trạng thái tương tự.

Cú pháp biểu diễn của memoized component giống như dưới đây:

const MemoizedComponent = memo(SomeComponent, arePropsEqual?);

Dưới đây là một ví dụ về các component con(EmployeeProfile) ngăn chặn việc render lại cho cùng props được truyền bởi component cha(EmployeeRegForm).

  import { memo, useState } from 'react';

  const EmployeeProfile = memo(function EmployeeProfile({ name, email }) {
    return (<>
          <p>Name:{name}</p>
          <p>Email: {email}</p>
          </>);
  });
  export default function EmployeeRegForm() {
    const [name, setName] = useState('');
    const [email, setEmail] = useState('');
    return (
      <>
        <label>
          Name: <input value={name} onChange={e => setName(e.target.value)} />
        </label>
        <label>
          Email: <input value={email} onChange={e => setEmail(e.target.value)} />
        </label>
        <hr/>
        <EmployeeProfile name={name}/>
      </>
    );
  }

Trong đoạn mã trên, thuộc tính email không được truyền cho component con. Vì vậy, sẽ không có bất kỳ render lại đối với component con khi thay đổi email.

Trong class component, các component được extend từ React.PureComponent thay vì React.Component sẽ trở thành các pure component. Khi props hoặc state thay đổi, PureComponent sẽ thực hiện so sánh nông(shallow comparison) trên cả props và state bằng cách gọi phương thức shouldComponentUpdate() của lifecycle.

Lưu ý: React.memo() là 1 higher-order component(HOC).

State trong React là gì?

State của một component là một đối tượng chứa một số thông tin có thể thay đổi trong suốt vòng đời(lifetime) của component. Điểm quan trọng là bất cứ khi nào state thay đổi, component đó sẽ được render lại. React luôn khuyến nghị làm cho state của component ở mức đơn giản nhất và số lượng các state nhỏ nhất có thể.

React state

Cùng xem component User trong ví dụ dưới đây, chúng ta sử dụng useState hook để quản lý trạng thái của message.

import { useState } from "react";

function User() {
  const [message, setMessage] = useState("Welcome to React world");

  return (
    <div>
      <h1>{message}</h1>
    </div>
  );
}

Mỗi khi trạng thái của message được thay đổi bằng cách gọi hàm setMessage thì component sẽ được render lại.

State tương tự như props, nhưng nó là private và được kiểm soát hoàn toàn bởi component, nó không thể truy cập bởi bất kỳ component nào khác bên ngoài nếu như component sở hữu nó không pass nó.

Props trong React là gì?

Props(viết tắt của properties) là dữ liệu đầu vào(input) của component, nó có thể là các giá trị riêng lẻ hoặc là một đối tượng chứa 1 tập các giá trị được truyền tới component tương tự như thuộc tính của thẻ HTML. Ở đây, dữ liệu được truyền từ component cha tới component con(one-way data flow).

Mục đích chính của props trong React là cung cấp chức năng sau:

  • Truyền dữ liệu tùy chỉnh(custom) cho component.
  • Trigger thay đổi state.

Dưới đây là 1 ví dụ về việc sử dụng props trong function component:

import React from "react";
import ReactDOM from "react-dom";

const ChildComponent = (props) => {
  return (
    <div>
      <p>{props.name}</p>
      <p>{props.age}</p>
      <p>{props.gender}</p>
    </div>
  );
};

const ParentComponent = () => {
  return (
    <div>
      <ChildComponent name="John" age="30" gender="male" />
      <ChildComponent name="Mary" age="25" geneder="female"/>
    </div>
  );
};

Các thuộc tính từ đối tượng props có thể được truy cập trực tiếp bằng cách sử dụng tính năng destructing từ ES6(ECMAScript 2015). Nó cũng có thể dự phòng(fallback) về giá trị mặc định khi giá trị trong prop không được chỉ định. ChildComponent ở trên có thể được viết lại như sau:

  const ChildComponent = ({name, age, gender="male"}) => {
      return (
        <div>
          <p>{name}</p>
          <p>{age}</p>
          <p>{gender}</p>
        </div>
      );
    };

Lưu ý: giá trị mặc định của prop sẽ không được sử dụng nếu bạn truyền giá trị null hoặc 0. Tức là giá trị mặc định chỉ được sử dụng nếu như giá trị trong prop bị bỏ qua(missed) hoặc được truyền giá trị là undefined.

Sự khác nhau giữa state và props trong React là gì?

Trong React, cả state và props đều là các đối tượng Javascript đơn giản và được sử dụng để quản lý dữ liệu của một component, nhưng chúng được sử dụng theo những cách khác nhau và có các đặc điểm khác nhau.

State được quản lý bởi chính component đó và có thể được cập nhật bằng hàm setter(setState() cho class component). Không giống như props, state có thể được sửa đổi bởi component và được sử dụng để quản lý trạng thái bên trong của component. Hơn nữa, những thay đổi về state sẽ trigger việc render lại của component và các thành phần con của nó. Các component sẽ không thể tái sử dụng được nếu chỉ sử dụng state.

Mặt khác, props được truyền cho một component bởi các component cha của nó và ở dạng chỉ đọc(readonly), nghĩa là chính component đó không thể sửa đổi props của nó. Ngoài ra, props có thể được sử dụng để cấu hình lại hành vi của một component và truyền dữ liệu giữa các component.

Tại sao chúng ta không nên cập nhật state một cách trực tiếp(directly)?

Nếu bạn có gắng cập nhật lại state 1 cách trực tiếp thì nó sẽ không render lại component.

//Wrong case
//Component doesn't re-render if we update the state directly
this.state.message = "Hello world";

Thay vào đó bạn phải sử dụng phương thức setState(nếu bạn sử dụng class component) hoặc phương thức setter(nếu bạn sử dụng function component) để cập nhật state cho component.

//Correct case
this.setState({ message: "Hello World" });
Avatar photo

Clean Code: Nguyên tắc đặt tên (Naming)

Clean Code là việc viết mã nguồn rõ ràng, dễ hiểu, dễ bảo trì. Bài viết này sẽ giới thiệu nguyên tắc đầu tiên...
Avatar photo Dat Tran Thanh
4 min read

Leave a Reply

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