이 글은 React에서 왜 함수형 컴포넌트(Hooks)가 사용되기 시작했는지에 관해 정리한 글입니다.
Hooks is new way to handle state and lifecycle.
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
So, What is the problem?
→ Syntactic sugar to hide Constructor / Prototype pattern
→ JavaScript is still prototype based language
ℹ️ There is no difference on how those code work.
function Monster(name) {
this.name = name;
}
Monster.prototype.attack
= function () {
console.log('attack!');
}
const monsterRat
= new Monster('rat');
monsterRat.attack();
// attack!
class Monster {
constructor(name) {
this.name = name;
}
attack() {
console.log('attack!');
}
}
const monsterRat
= new Monster('rat');
monsterRat.attack();
// attack!
this
in JavaScriptthis
, aka “the context”, is a special keyword inside each function and its value only depends on how the function was called, not how/when/where it was defined.function foo() { console.log(this); }
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo}
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
this
this
bindingthis
is looked up in scope just like a normal variable = don’t have to call bind
function MyConstructor(data, transport) {
this.data = data;
tansport.on('data', () => alert(this.data));
}
this
of the callbackEvery function has the method [.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)
, which returns a new function with this
bound to a value
this
will always refer to the passed value
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() {
alert(this.data);
}).bind(this); // call `.bind()`
transport.on('data', boundFunction);
}
this
this
? We want to access the object it refers tofunction MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
function Foo() {
this.data = 42;
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
The function this.method
is assigned as click event handler, but if the document.body
is clicked, the value logged will be undefined
, because inside the event handler, this
refers to the document.body
, not the instance of Foo
.
If you want to specify this
, you can do one of following.
document.body.conclick = this.method.bind(this);
// or
document.body.onclick = () => this.method();
Again,
What
this
refers to depends on how the function is called, not how it is defined.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
}
// bind method
// this.handleClick = this.handleClick.bind(this);
}
// error
handleClick() {
this.setState({count: this.state.count + 1});
}
render() {
return (
<div>
<h4>{this.state.count}</h4>
<button type='button' onClick={this.handleClick}>
Click Me!
</button>
</div>
)
}
}
Props are immutable in React so they can never change. However,
this
is, and has always been, mutable.
componentDidMount
and remove them in componentWillUnmount
. Hooks let you combine these twoFunction components capture the rendered values
React passes them as an argument. Unlike
this
, theprops
object itself is never mutated by React.
function MyComponent() {
const ref = React.useRef(null);
// You can read or write `ref.current`.
// ...
}
State Management: In class components, state was managed using the this.state
object and the this.setState()
method. With hooks, functional components can use the useState
hook to define and update state. The useState
hook returns an array with the current state value and a function to update it. This simplifies the syntax and eliminates the need for class-based state management.
function MyComponent() {
const [state, setState] = React.useState(/*initial value*/);
// ...
}
Lifecycle and Side Effects: Class components had lifecycle methods like componentDidMount
, componentDidUpdate
, and componentWillUnmount
for handling side effects and component lifecycle events. With hooks, functional components can use the useEffect
hook to manage side effects and mimic component lifecycle. The useEffect
hook allows you to perform actions when the component mounts, updates, or unmounts. It replaces multiple lifecycle methods with a single hook, resulting in more concise and focused code.
componentDidMount() { ... }
useEffect(() => { ... }, [])
componentWillUnmount() { ... }
useEffect(() => { return () => { ... } }, [])
componentDidUpdate() { ... }
useEffect(() => { ... })
Performance Optimization: Hooks provide optimizations such as memoization and fine-grained control over component updates. Hooks like useMemo
and useCallback
allow you to memoize expensive computations and prevent unnecessary re-renders. This can lead to better performance and more efficient rendering compared to class components.
Premature optimizations are the root of all evil - worry about this when it's a problem.
When to use ES6 class based React components vs. functional ES6 React components?
How does the "this" keyword work, and when should it be used?
An Visual Guide to JavaScript Constructor / Prototype Pattern
this
😜this
in javascript dynamic value?