React Hook

Trần Đức Lĩnh

I) Kiến thức tổng quát.

  • Khái niệm cơ bản React hooks

    • Là mọt function được hook-into vào các features của Reactjs được gọi cần thiết.
    • Được thêm vào từ phiên bản 16.8.
    • Giúp sử dụng state, prop, lifecycle, features mà không cần đụng tới class.
  • Khi nào dùng Hooks

    • Đơn giản là không thích làm việc với OOP(class).
    • (Chỉ được dùng cho functions component, không dùng cho class).
  • Tại sao dùng Hooks

    • Không bị bearking changes.
    • Có thể dùng class conponent cũ vừa dùng thử nghiệm react hooks cho component mới.
    • Loại bỏ rào cản OOP (this, constructor, super...).
    • Không có kế hoạch loại bỏ class component.
    • Không xoá bỏ kiến thức đã biết về state, life cycle, context,...

II) use.

  • useState()

    • Công dụng

      • Là một hook cơ bản.
      • Có thể dùng state trong functonal component.
      • Input: InitialState (Giá trị hoặc function).
      • Output: một mảng có 2 phần tử tương ứng cho state và setState.
      • Cú pháp:

        const [<name>, <setName>] = useState('<Object_Name>');
    • Lưu ý khi sử dụng useState()

      • useState() áp dụng Replacing thay vì Mergin như bên class.

        • Khắc phục khi xảy ra lỗi.

          • Sử dụng Spread & Rest.
      • Initial state chỉ dùng cho lần đầu, những lần sau không có ý nghĩa gì.

        • Sử dụng callback chỉ chạy đúng 1 lần duy nhất, không phải render nhiều lần.
  • Liên quan đến Array Destructoring syntax

    • Ví dụ

      • const [a, b] = ['Hello', 'Word'];
  • useEffect()

    • Liên quan đến Side effect.

      • Dùng để.

        • Gọi API để lấy dữ liệu.
        • Tương tác với DOM.
        • Subcripttions.
        • setTimeout, setInterval.
    • Có 2 loại bao gồm.

      • Effect (không cần clean up).

        • Gọi API, tương tác DOM.
      • Effect (cần clean up).

        • Subscriptions, setTiemout, setInterval.
    • Công dụng.

      • Là một hook cơ bản trong React hooks, hỗ trợ cho Functional Components.
      • Sử dụng cho Side effects.
      • useEffect có 2 phần.

        • side effect.
        • clean up (optional).
      • Được thực thi sau mỗi lần render.
      • Được thực thi ít nhất 1 lần sau lần render đầu tiên.
      • Những lần render tiếp theo chỉ được thực thi nếu có dependencies thay đổi.
      • Effect cleanup sẽ được thực thị trước khi run effect lần tiếp theo hoặc unmuont.
      • Có thể sử dụng nhiều useEffect() trong cùng một component.
    • Cú pháp

      • function useEffect(callback, dependencies).
    • Ví dụ:
    function App() {
    // executed before each render
    const [color, setColor] = useState('deeppink');
    // executed after each render
    
    useEffect(() => {
        // do your side effect here ...
        return () => {
            // Clean up here ...
            // Executed before the next render or unmount
        };
    }, []);
    
        // rendering
        return <h1>Hello</h1>;
    }
    • Giải thích ví dụ.

      • Mounting.

        • (rendering) lần đầu tiên.
        • Chỉ khởi chạy useEffect() tại Side effect. Không chạy phần return() bên trong useEffect().
      • Updating.

        • (rendering) lần tiếp theo.
        • Khởi chạy (useEffect() cleanup) nếu dependencies thay đổi.
        • Khởi chạy (useEffect()) nếu dependencies thay đổi.
      • Unmounting.

        • Khởi chạy (useEffect() cleanup) .
    • Những trường hợp của (Dependencies).

      • Trường hợ không có Dependencies.

        • Điều đó có nghĩa useEffect luôn luôn được chạy sau mỗi lần render.
      • Trường hợp khai báo Dependencies một mảng rỗng.

        • Điều đó có nghĩa useEffect chỉ chạy đúng một lần sau lần render đầu tiên.
        • Và chỉ chạy đúng một lần sau khi unmount.
      • Trường hợp khai báo Dependencies có tham số.

        • Điều đó có nghĩa vẫn render sau mỗi lần chạy, các lần tiếp theo sẽ phụ thuộc vào thay đổi của tham số truyền vào để căn cứ có chạy tiếp theo hoặc không, (thông thường sẽ theo dỗi thay đổi trong state).
    • Chuyển từ life cycles sang useEffect()

      • componentDidMount() và componentWillUnmount()
      useEffect(() => {
      //
      }; 
          return () => {
          //
          };
      }, []);
      • componentDidMount() và componentDidUpdate()
      useEffect(() => {
      //
      });
  • useContext()

    • Khái niệm.

      • Cơ chế để tạo các biến toàn cục có thể được truyền qua trong ứng dụng ReactJS, phương pháp thay thế cho "prop drilling" hoặc truyền props từ ông nội sang cha và sang con, v..v...
      • useContext() thường được coi là đơn giản hơn, nhẹ nhàng hơn Redux cho việc quản lý state.
      • Dùng cho việc share “global” data, ví dụ như authenticated user, theme, language,… Những data này đơn giản không phức tạp và ít khi được thay đổi.
    • Lưu ý.

      • Giống như Redux, cần tạo Context ở bậc cao nhất, từ đó mới có thể chia sẻ đến các component thấp hơn.
      • Sau đó sử dụng Provider bọc các component cấp thấp hơn, tiện cho việc chia sẻ state.
    • Phân phát.

      • UserContext.Provider.
      • export const UserContext = React.createUseContext().
      <UserContext.Provider value='example'>
      <Component />
      </UserContext.Provider>
    • Đón nhận.

      • UserContext.Consumer.
      • Nhận Component.
      import {UsesContext} from '../App';
      
      <UserContext.Consumer>
      {
          user => (
              <div>{user}</div>
          )
      }
      </UserContext.Consumer>
      • Nhận Values.
      import React, {useContext} from 'react';
      import {UserContext} from '../App';
      
      const user = useContext(UserContext)
  • useReducer()

    • Khái niệm.

      • useReducer() và Redux không liên quan đến nhau.
      • Là một hàm có 2 tham số là state và action và trả về một new state.
      • Nói ngắn gọn là dùng useState theo kiểu Redux.
    • Ví dụ:

      • Reducer.
      const countReducer = (state, action) => {
          switch (action.type) {
              case "INCREASE":
              return {
                  ...state,
                  count: state.count + 1
              };
              case "DECREASE":
              return {
                  ...state,
                  count: state.count - 1
              };
              default:
              throw new Error();
          }
      };
      
      export default countReducer;
      • useReducer.
      import React, { useReducer } from "react";
      import countReducer from "./state";
      
      export default function App() {
          const [state, dispatch] = useReducer(countReducer, { count: 0 });
      
          const handleClickIncrease = () => {
              dispatch({ type: "INCREASE" });
          };
      
          const handleClickDecrease = () => {
              dispatch({ type: "DECREASE" });
          };
      
          return (
              <>
              <div className="App">
                  <h1>Hello {state.count}</h1>
              </div>
              <div>
                  <button onClick={handleClickIncrease}>+</button>
                  <button onClick={handleClickDecrease}>-</button>
              </div>
              </>
          );
      }
  • Memoization

    • Khái niệm

      • Tăng tốc độ xử lý các vấn đề cho máy tính bằng cách lưu trữ dữ liệu đã tính toán trước đó và không lặp lại tương tự ở các lần tiếp theo.
      • Khi gặp bộ tính toán ban đầu, sau đó sẽ lưu vào bô nhớ đệm, nếu gặp bộ tính toán tiếp theo giống với bộ tính toán ban đầu sẽ không tính toán lại mà return ngay kết quả của bộ tính toán ban đầu.
    • Ví dụ:
    const addMemo = (a, b) => {
    
        if(!addMemo.cache) {
            addMemo.cache = {};
        }
    
        const key = `${a}_${b}`;
        const synmetriKey = `${b}_${a}`;
        if (addMemo.cache[key]) return addMemo.cache[key];
        if (addMemo.cache[synmetriKey]) return addMemo.cache[synmetriKey];
    
        const sum = a + b;
        addMemo.cache[key] = sum;
        addMemo.call[synmetriKey] = sum;
        return sum;
    
    }
    
    addMemo(2,3);
    addMemo(3,2);
  • React.memo()

    • Khái niệm.

      • Nó là một HOC, không phải hooks.
      • Tương tự như PureComponent.
      • Sử dụng cho functional component.
      • Chỉ render lại nếu props thay đổi.
      • Sử dụng so sánh nông (shalow comparison).
    • Sử dụng.

      • Hạn chế một phần không đáng kể.
      • Dùng lý tưởng trong các component liên quan đến đồ thị, tính toán phức tạp.
    • Nhược điểm

      • Call function trong onClick(), khi này sẽ xảy ra trường hợp re-render ở các lần tiếp theo
    • Ví dụ:
    function Example () {
        return (
            <div>Hello world</div>
        )
    }
    
    export default React.memo(Example)
  • useCallback()

    • Khái niệm.

      • Là một React hooks.
      • Giúp tạo ra memoized callback và chỉ tạo ra callback mới khi dependencies thay đổi.
      • Trả về memoized callback.
      • Hạn chế những lần re-render dư thừa.
    • Cách thức hoạt động.

      • Nhận vào 2 tham số là funtion và dependencies.
      • Return memoized callback.
      • Chỉ tạo ra function mới khi dependencies thay đổi.
      • Nếu dùng empty dependencies thì không bao giờ tạo ra function mới.
    • Lưu ý.

      • Chỉ dùng cho các tác vụ nặng, biểu đồ, animations.
    • Ví dụ:

      • Trường hợp xấu.
      function App () {
          const handleBuild = (type) => {};
          return <Build onTypeChange={handleBuild} />;
      }
      • Cải thiện.
      function App () {
          const handleBuild = useCallback(
              (type) => {},
              [],
          )
          return <Build onTypeChange={handleBuild} />;
      }
  • useMemo()

    • Khái niệm.

      • Là một React hooks.
      • Giúp tạo ra memoized value và chỉ tính toán ra value mới khi dependencies thay đổi.
      • Trả về memoized value.
      • Hạn chế những lần re-render dư thừa.
    • Cách thức hoạt động.

      • Nhận vào 2 tham số là funtion và dependencies.
      • Return memoized value.
      • Chỉ tính toán value mới khi dependencies thay đổi.
      • Nếu dùng empty dependencies thì không bao giờ tạo ra value mới.
    • Ví dụ:

      • Trường hợp xấu:
      function App () {
          const data = [{}, {}, {}];
          return <Build data={data} />;
      }
      • Cải thiện:
      function App () {
          const data = useMemo(() => [{}, {}, {}], []);
          return <Build data={data} />;
      }
  • useRef()

    • Khái niệm.

      • refs được sử dụng để lấy tham chiếu đến một node DOM hoặc thể hiện của một component trong một ứng dụng React.
      • Nói cách khác refs sẽ return về một node mà chúng có thể tham chiếu đến.
      • useRef trả về một ref object và được lưu giữ trong suốt vòng đời của component.
    • Ví dụ:
    import { useEffect, useRef } from "react";
    
    export default function App() {
    
        const inputRef = useRef(null);
    
        useEffect(() => {
            inputRef.current.focus()
        }, [])
    
        return (
            <div className="App">
            <input ref={inputRef} type='text' />
            </div>
        );
    }
  • Custom Hook

    • Khái niệm.

      • A custom Hook is basically a JavaScript function whose name starts with "use".
      • A custom Hook can also call other Hooks if required.
    • Why?.

      • Share logic - Alternative to HOCs and Render Props.
    • Xây dựng.

      • Được bắt đầu với "use".
    • Cấu trúc thư mục.

    • Ví dụ:

      • useCount.js
      import { useState } from "react";
      
      function useCounter(initialCount = 0) {
          const [count, setCount] = useState(initialCount);
      
          const countPlus = () => {
              setCount((prevCount) => prevCount + 1);
          };
      
          const reset = () => {
              setCount(0);
          };
      
          return [count, countPlus, reset];
      };
      
      export default useCounter;
      • App.js
      import useCounter from "../hook/useCounter";
      
      export default function App() {
          const [count, countPlus, reset] = useCounter();
      
          return (
              <div className="App">
              <h1>{count}</h1>
              <button onClick={countPlus}>Count</button>
              <button onClick={reset}>Reset</button>
              </div>
          );
      }

(Chỉnh sửa nếu có...)