Back to Blog

Hướng dẫn React Hooks từ cơ bản đến nâng cao

Minh Duy
Published on January 12, 2025
5 min read
Hướng dẫn React Hooks từ cơ bản đến nâng cao
Web Development
React
Hooks
JavaScript
Frontend

Hướng dẫn React Hooks từ cơ bản đến nâng cao

React Hooks đã thay đổi cách chúng ta viết React components. Trong bài viết này, chúng ta sẽ tìm hiểu từ những khái niệm cơ bản đến các kỹ thuật nâng cao.

React Hooks là gì?

React Hooks là các function đặc biệt cho phép bạn "hook into" các tính năng của React từ functional components. Hooks được giới thiệu trong React 16.8.

Tại sao sử dụng Hooks?

  • Đơn giản hóa code: Không cần class components
  • Tái sử dụng logic: Dễ dàng chia sẻ logic giữa components
  • Dễ test: Functional components dễ test hơn
  • Performance tốt hơn: Ít overhead hơn class components

Các Hook cơ bản

useState Hook

Quản lý state trong functional components:

function Counter() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');

  return (
    <div>
      <p>Bạn đã click {count} lần</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
      
      <input 
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Nhập tên của bạn"
      />
    </div>
  );
}

useEffect Hook

Xử lý side effects trong components:

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  // Effect chạy sau mỗi render
  useEffect(() => {
    fetchUser(userId)
      .then(userData => {
        setUser(userData);
        setLoading(false);
      });
  }, [userId]); // Dependency array

  // Effect cleanup
  useEffect(() => {
    const timer = setInterval(() => {
      console.log('Timer tick');
    }, 1000);

    return () => {
      clearInterval(timer); // Cleanup
    };
  }, []);

  if (loading) return <div>Đang tải...</div>;
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

useContext Hook

Sử dụng React Context dễ dàng hơn:

// Tạo Context
const ThemeContext = createContext();

// Provider component
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// Component sử dụng Context
function ThemedButton() {
  const { theme, setTheme } = useContext(ThemeContext);

  return (
    <button 
      style={{ 
        backgroundColor: theme === 'light' ? '#fff' : '#333',
        color: theme === 'light' ? '#333' : '#fff'
      }}
      onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
    >
      Chuyển đổi theme ({theme})
    </button>
  );
}

Các Hook nâng cao

useReducer Hook

Quản lý state phức tạp với reducer pattern:

// Reducer function
function todoReducer(state, action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [...state, { 
        id: Date.now(), 
        text: action.text, 
        completed: false 
      }];
    case 'TOGGLE_TODO':
      return state.map(todo =>
        todo.id === action.id 
          ? { ...todo, completed: !todo.completed }
          : todo
      );
    case 'DELETE_TODO':
      return state.filter(todo => todo.id !== action.id);
    default:
      return state;
  }
}

function TodoApp() {
  const [todos, dispatch] = useReducer(todoReducer, []);
  const [inputText, setInputText] = useState('');

  const addTodo = () => {
    if (inputText.trim()) {
      dispatch({ type: 'ADD_TODO', text: inputText });
      setInputText('');
    }
  };

  return (
    <div>
      <input 
        value={inputText}
        onChange={(e) => setInputText(e.target.value)}
        placeholder="Thêm công việc mới"
      />
      <button onClick={addTodo}>Thêm</button>
      
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            <span 
              style={{ 
                textDecoration: todo.completed ? 'line-through' : 'none' 
              }}
              onClick={() => dispatch({ type: 'TOGGLE_TODO', id: todo.id })}
            >
              {todo.text}
            </span>
            <button 
              onClick={() => dispatch({ type: 'DELETE_TODO', id: todo.id })}
            >
              Xóa
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Custom Hooks

Tạo custom hooks để tái sử dụng logic:

// Custom hook cho API calls
function useApi(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch(url);
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

// Custom hook cho local storage
function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      return initialValue;
    }
  });

  const setValue = (value) => {
    try {
      setStoredValue(value);
      window.localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.error(error);
    }
  };

  return [storedValue, setValue];
}

Best Practices

Rules of Hooks

  1. Chỉ gọi Hooks ở top level - Không gọi trong loops, conditions, hoặc nested functions
  2. Chỉ gọi Hooks từ React functions - Components hoặc custom Hooks

Performance Tips

// ✅ Good: Dependency array chính xác
useEffect(() => {
  fetchData(userId);
}, [userId]);

// ❌ Bad: Missing dependency
useEffect(() => {
  fetchData(userId);
}, []); // userId should be in dependency array

// ✅ Good: Sử dụng useCallback cho event handlers
const handleClick = useCallback(() => {
  doSomething(value);
}, [value]);

// ✅ Good: Sử dụng useMemo cho expensive calculations
const expensiveValue = useMemo(() => {
  return heavyCalculation(data);
}, [data]);

Kết luận

React Hooks đã làm cho việc viết React components trở nên đơn giản và mạnh mẽ hơn. Với việc hiểu rõ các hooks cơ bản và nâng cao, bạn có thể:

  • Viết code React sạch và dễ maintain
  • Tái sử dụng logic hiệu quả với custom hooks
  • Tối ưu hóa performance với useMemo và useCallback
  • Quản lý state phức tạp với useReducer

Hãy thực hành thường xuyên và áp dụng các best practices để trở thành React developer giỏi hơn!

Chúc bạn coding vui vẻ! 🚀

Related Posts