{"data":{"slug":"react-hooks-first-look","title":{"vi":"React Hooks — cái nhìn đầu tiên và tại sao nó thay đổi mọi thứ","en":"React Hooks — A First Look and Why It Changes Everything"},"excerpt":{"vi":"React Hooks vừa được giới thiệu tại React Conf 2018. useState, useEffect và custom hooks hứa hẹn sẽ thay đổi hoàn toàn cách chúng ta viết component.","en":"React Hooks were just introduced at React Conf 2018. useState, useEffect, and custom hooks promise to completely change the way we write components."},"content":{"vi":["## Hooks là gì?","Tại React Conf 2018, đội ngũ React chính thức giới thiệu Hooks — một API mới cho phép bạn sử dụng state và các tính năng khác của React mà không cần viết class component. Đây là thay đổi lớn nhất kể từ khi React ra đời.","Trước Hooks, nếu muốn dùng state trong component, bạn bắt buộc phải dùng class. Function component chỉ có thể nhận props và render JSX — không hơn không kém. Hooks thay đổi hoàn toàn điều đó.","## `useState` — state không cần class","Hook cơ bản nhất là `useState`. Thay vì khai báo `this.state` trong constructor và gọi `this.setState`, bạn chỉ cần một dòng:","```js\nconst [count, setCount] = useState(0);\n```","Mỗi lần gọi `setCount`, React sẽ re-render component với giá trị mới. Bạn có thể dùng nhiều `useState` cho nhiều giá trị khác nhau thay vì gom tất cả vào một object lớn:","```js\nfunction Profile() {\n  const [name, setName] = useState('');\n  const [age, setAge] = useState(0);\n  const [isOnline, setIsOnline] = useState(false);\n\n  return (\n    <div>\n      <input value={name} onChange={e => setName(e.target.value)} />\n      <p>{name}, {age} tuổi — {isOnline ? 'Online' : 'Offline'}</p>\n    </div>\n  );\n}\n```","Đơn giản, trực quan và dễ đọc hơn rất nhiều so với class component.","Thử tương tác với counter bên dưới — mỗi lần nhấn, `useEffect` sẽ cập nhật document title:","{{demo:counter}}","## `useEffect` — thay thế lifecycle methods","`useEffect` kết hợp `componentDidMount`, `componentDidUpdate` và `componentWillUnmount` vào một API duy nhất. Bạn khai báo side effects trực tiếp trong function component:","```js\nuseEffect(() => {\n  // Chạy sau mỗi lần render\n  document.title = `Bạn đã click ${count} lần`;\n}, [count]); // Chỉ chạy lại khi count thay đổi\n```","Dependency array `[count]` là phần quan trọng nhất — nó cho React biết effect chỉ cần chạy lại khi `count` thay đổi, tránh chạy thừa sau mỗi lần render.","Cleanup cũng rất dễ — chỉ cần return một function:","```js\nuseEffect(() => {\n  const subscription = ChatAPI.subscribe(userId);\n\n  // Cleanup khi component unmount hoặc userId thay đổi\n  return () => {\n    ChatAPI.unsubscribe(userId);\n  };\n}, [userId]);\n```","## Custom Hooks — chia sẻ logic giữa các component","Điểm mạnh thực sự của Hooks nằm ở custom hooks. Bạn có thể extract logic stateful ra thành một function riêng và tái sử dụng ở bất cứ đâu.","Ví dụ, hook theo dõi kích thước window:","```js\nfunction useWindowSize() {\n  const [size, setSize] = useState({\n    width: window.innerWidth,\n    height: window.innerHeight,\n  });\n\n  useEffect(() => {\n    const handleResize = () => {\n      setSize({\n        width: window.innerWidth,\n        height: window.innerHeight,\n      });\n    };\n\n    window.addEventListener('resize', handleResize);\n    return () => window.removeEventListener('resize', handleResize);\n  }, []);\n\n  return size;\n}\n```","Giờ bất kỳ component nào cũng có thể dùng `const { width, height } = useWindowSize()` mà không cần render props hay HOC.","## Quy tắc của Hooks","React đặt ra hai quy tắc bắt buộc khi dùng Hooks:","**1. Chỉ gọi Hooks ở top level** — không gọi trong vòng lặp, điều kiện, hay function lồng nhau. React dựa vào thứ tự gọi Hooks để map đúng state.","**2. Chỉ gọi Hooks trong React function** — trong function component hoặc custom hooks, không phải function JavaScript thông thường.","ESLint plugin `eslint-plugin-react-hooks` giúp bạn phát hiện vi phạm ngay trong quá trình code.","## So sánh: Class vs Hooks","Hãy xem cùng một logic counter, viết bằng class và bằng hooks:","```js\n// Class component — 20+ dòng\nclass Counter extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = { count: 0 };\n  }\n\n  componentDidMount() {\n    document.title = `Count: ${this.state.count}`;\n  }\n\n  componentDidUpdate() {\n    document.title = `Count: ${this.state.count}`;\n  }\n\n  render() {\n    return (\n      <button onClick={() => this.setState({ count: this.state.count + 1 })}>\n        {this.state.count}\n      </button>\n    );\n  }\n}\n```","```js\n// Function component + Hooks — 10 dòng\nfunction Counter() {\n  const [count, setCount] = useState(0);\n\n  useEffect(() => {\n    document.title = `Count: ${count}`;\n  }, [count]);\n\n  return <button onClick={() => setCount(count + 1)}>{count}</button>;\n}\n```","Ít code hơn, logic tập trung hơn, không còn phải lo `this` binding.","## Tại sao Hooks thay đổi mọi thứ?","Hooks giải quyết nhiều vấn đề tồn tại lâu năm: class component phức tạp, logic bị phân tán trong lifecycle methods, và khó khăn khi chia sẻ stateful logic giữa các component.","Đội ngũ React khẳng định Hooks không phải breaking change — class component vẫn hoạt động bình thường. Nhưng xu hướng rõ ràng là hướng về function component + Hooks cho code mới. Đây là tương lai của React."],"en":["## What are Hooks?","At React Conf 2018, the React team officially introduced Hooks — a new API that lets you use state and other React features without writing class components. This is the biggest change since React was born.","Before Hooks, if you wanted state in a component, you had to use a class. Function components could only receive props and render JSX — nothing more. Hooks change that entirely.","## `useState` — state without classes","The most basic hook is `useState`. Instead of declaring `this.state` in a constructor and calling `this.setState`, you just need one line:","```js\nconst [count, setCount] = useState(0);\n```","Each time you call `setCount`, React re-renders the component with the new value. You can use multiple `useState` calls for different values instead of cramming everything into one large object:","```js\nfunction Profile() {\n  const [name, setName] = useState('');\n  const [age, setAge] = useState(0);\n  const [isOnline, setIsOnline] = useState(false);\n\n  return (\n    <div>\n      <input value={name} onChange={e => setName(e.target.value)} />\n      <p>{name}, {age} years old — {isOnline ? 'Online' : 'Offline'}</p>\n    </div>\n  );\n}\n```","Simple, intuitive, and far more readable than class components.","Try interacting with the counter below — each click triggers `useEffect` to update the document title:","{{demo:counter}}","## `useEffect` — replacing lifecycle methods","`useEffect` combines `componentDidMount`, `componentDidUpdate`, and `componentWillUnmount` into a single API. You declare side effects directly in your function component:","```js\nuseEffect(() => {\n  // Runs after every render\n  document.title = `You clicked ${count} times`;\n}, [count]); // Only re-run when count changes\n```","The dependency array `[count]` is the most important part — it tells React the effect only needs to re-run when `count` changes, avoiding unnecessary runs after every render.","Cleanup is also straightforward — just return a function:","```js\nuseEffect(() => {\n  const subscription = ChatAPI.subscribe(userId);\n\n  // Cleanup when component unmounts or userId changes\n  return () => {\n    ChatAPI.unsubscribe(userId);\n  };\n}, [userId]);\n```","## Custom Hooks — sharing logic between components","The real power of Hooks lies in custom hooks. You can extract stateful logic into a separate function and reuse it anywhere.","For example, a hook that tracks window size:","```js\nfunction useWindowSize() {\n  const [size, setSize] = useState({\n    width: window.innerWidth,\n    height: window.innerHeight,\n  });\n\n  useEffect(() => {\n    const handleResize = () => {\n      setSize({\n        width: window.innerWidth,\n        height: window.innerHeight,\n      });\n    };\n\n    window.addEventListener('resize', handleResize);\n    return () => window.removeEventListener('resize', handleResize);\n  }, []);\n\n  return size;\n}\n```","Now any component can use `const { width, height } = useWindowSize()` without render props or HOCs.","## Rules of Hooks","React enforces two mandatory rules when using Hooks:","**1. Only call Hooks at the top level** — don't call them inside loops, conditions, or nested functions. React relies on the order of Hook calls to correctly map state.","**2. Only call Hooks from React functions** — inside function components or custom hooks, not regular JavaScript functions.","The ESLint plugin `eslint-plugin-react-hooks` helps you catch violations right in your editor.","## Comparison: Class vs Hooks","Let's see the same counter logic written with a class and with hooks:","```js\n// Class component — 20+ lines\nclass Counter extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = { count: 0 };\n  }\n\n  componentDidMount() {\n    document.title = `Count: ${this.state.count}`;\n  }\n\n  componentDidUpdate() {\n    document.title = `Count: ${this.state.count}`;\n  }\n\n  render() {\n    return (\n      <button onClick={() => this.setState({ count: this.state.count + 1 })}>\n        {this.state.count}\n      </button>\n    );\n  }\n}\n```","```js\n// Function component + Hooks — 10 lines\nfunction Counter() {\n  const [count, setCount] = useState(0);\n\n  useEffect(() => {\n    document.title = `Count: ${count}`;\n  }, [count]);\n\n  return <button onClick={() => setCount(count + 1)}>{count}</button>;\n}\n```","Less code, more focused logic, no more worrying about `this` binding.","## Why do Hooks change everything?","Hooks solve many long-standing problems: complex class components, logic scattered across lifecycle methods, and difficulty sharing stateful logic between components.","The React team confirmed that Hooks are not a breaking change — class components still work perfectly. But the trend is clearly toward function components + Hooks for new code. This is the future of React."]},"date":"2018-11-20","readTime":6,"tags":["React","JavaScript"]}}