201008_TIL
Today I learned
- React Hooks
- Hooks
- useState Hooks
- useEffect Hooks
- Hooks 사용규칙
- Custom Hooks
- React Hooks
- Hooks
- useState Hooks
- useEffect Hooks
- Hooks 사용규칙
- Custom Hooks
@@ 오늘은 Recase.ly 스프린트(유투브 API 연동, React class 컴포넌트 구성)를 마무리 짓고, react의 Hooks 에 대해서 공식문서를 읽으며 정리하는 시간을 가졌다.
강의를 듣기 전에 독학할때 인강으로도 보고, 책도 읽고 했었지만 최적화 하는 부분에서 너무 어렵게만 느껴지고 굳이 이것을 써야하나? 클래스 컴포넌트가 더 나은 것 같은데.. 라고 생각하고는 했었는데 공식문서가 이토록 자세하고 친절한지 몰랐다. 공식문서에 대한 현기증으로.. 멀리만했었기 때문인 것 같다. 공식 문서 및 레슨을 들으면서 왜 Hooks가 필요한지, 클래스 컴포넌트는 어떤 문제가 있는지 살펴보니 (그러니까... 이유를 알고 배우니) 더 친절하게 느껴지고, 이해도 더 잘가는 기분이었다.
남은 시간은 recast.ly의 Advanced 부분을 진행해보려는 훅스에 도전해봐야겠다.
참, 그리고 #velog
의 화면 사이즈가 변할때마다 작성하던 글이 다 날라가는 게 너무 불편했었더니 오늘보니 수정되었는지, 해당 버그가 없어졌다. 😊 작은 문제이지만 은근히.. 불편했는데 작은것에 행복해지는.. 추가적으로 바람이 있다면, 접근성 규칙에 맞춰서 제목에서 탭으로 순서대로 이동할 수 있도록도 변경되면 좋겠다. (제목-> 태그-> 본문)
지금은... 왜그런지 모르겠는데 탭하면 순서가 이상하게 잡혀있는 것 같다. (이것도 사소한 불편함...)
Hooks
- Hook은 함수 컴포넌트에서 React state와 생명주기 기능(lifecycle features)을 “연동(hook into)“할 수 있게 해주는 함수
- 새로 작성하는 컴포넌트부터는 Hook을 이용
useState Hooks
import React, { useState } from 'react';
function Example() {
// 새로운 state 변수를 선언하고, 이것을 count라 부르겠습니다.
const [count, setCount] = useState(0);
-
useState는 state를 함수 컴포넌트 안에서 사용할 수 있게 해준다.
-
state를 추가하고 싶을 때 클래스 컴포넌트로 바꾸지 않고 useState
훅을 사용하면 state를 사용할 수 있다.
-
함수 컴포넌트는 this를 가질 수 없기 때문에 useState 훅을 직접 호출해야 한다.
-
useState를 호출하는 것은 state변수를 선언하는 것과 같다.
-
선언한 변수의 이름은 사용자가 지을 수 있다.
-
일반적으로 일반 변수는 함수가 종료될 때 사라지지만 state변수는 리액트에 의해 사라지지 않는다.
-
구조 분해 할당으로 state 변수, 해당 변수를 갱신할 수 있는 함수를 받는다. 구조분해할당에 대한 코드의 의미는 아래의 코드와 같다.
var fruitStateVariable = useState('banana'); // 두 개의 아이템이 있는 쌍을 반환
var fruit = fruitStateVariable[0]; // 첫 번째 아이템
var setFruit = fruitStateVariable[1]; // 두 번째 아이템
-
useState에 들어가는 인자값은 state 변수의 초기값으로 할당된다.
-
아래와 같은 방법으로 설정한 state값을 가져올 수 있다.
<p>You clicked {count} times</p>
- state값 갱신 방법
<button onClick={() => setCount(count + 1)}>
Click me
</button>
- useState 의 state갱신함수는 값을 병합하는 것이 아니라 대체한다.
useEffect Hooks
-
useEffect는 함수 컴포넌트 내에서 이런 side effects를 수행할 수 있게 해준다
-
React class의 componentDidMount 나 componentDidUpdate, componentWillUnmount와 같은 목적으로 제공되지만, 하나의 API로 통합
-
Effect를 “해제”할 필요가 있다면, 해제하는 함수를 반환
-
이 반환되는 함수는 컴포넌트가 Unmount 될때, 그리고 재 렌더링이 일어나 effect를 재실행하기 전에 실행된다.
-
클래스의 하나의 로직에 여러개 함수를 써야한다는 복잡성때문에 탄생하게 되었다.
-
useState와 마찬가지로 컴포넌트 내에서 여러 개의 effect를 사용할 수 있다.
function FriendStatusWithCounter(props) {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
// ...
}
- Hooks를 사용하면 생명주기 메서드가 아닌 코드 로직에 따라 처리를 할 수 있다.
effect가 업데이트 시마다 실행되는 이유
- 클래스 컴포넌트에서 발생하는 버그를 해결하기 위해 effect 는 업데이트 시마다 실행된다.
- 클래스 일때 생명주기 메소드 예시
componentDidMount() {
ChatAPI.subscribeToFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}
componentWillUnmount() {
ChatAPI.unsubscribeFromFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}
-
컴포넌트가 화면에 표시되어있는 동안 friend prop 이 변한다면 컴포넌트는 온라인 상태로 잘못 표시하게 되고, 언마운트 될 때 다른 사용자가 해지되는 등의 충돌이 일어날 수 있다. 그래서 이를 막기 위해 componentDidUpdate 메소드를 사용하는데 이 또한 버그 중의 하나로 제대로 작동 되지 않는다.
-
useEffect는 업데이트를 다루기 때문에 이런 버그 들을 해결할 수 있다.
-
다음 effect를 적용하기 전 이전의 effect 는 정리 한다.
-
코드로 나타나면 다음과 같다
import React, { useState } from 'react';
function Example() {
// 새로운 state 변수를 선언하고, 이것을 count라 부르겠습니다.
const [count, setCount] = useState(0);
-
useState는 state를 함수 컴포넌트 안에서 사용할 수 있게 해준다.
-
state를 추가하고 싶을 때 클래스 컴포넌트로 바꾸지 않고
useState
훅을 사용하면 state를 사용할 수 있다. -
함수 컴포넌트는 this를 가질 수 없기 때문에 useState 훅을 직접 호출해야 한다.
-
useState를 호출하는 것은 state변수를 선언하는 것과 같다.
-
선언한 변수의 이름은 사용자가 지을 수 있다.
-
일반적으로 일반 변수는 함수가 종료될 때 사라지지만 state변수는 리액트에 의해 사라지지 않는다.
-
구조 분해 할당으로 state 변수, 해당 변수를 갱신할 수 있는 함수를 받는다. 구조분해할당에 대한 코드의 의미는 아래의 코드와 같다.
var fruitStateVariable = useState('banana'); // 두 개의 아이템이 있는 쌍을 반환
var fruit = fruitStateVariable[0]; // 첫 번째 아이템
var setFruit = fruitStateVariable[1]; // 두 번째 아이템
-
useState에 들어가는 인자값은 state 변수의 초기값으로 할당된다.
-
아래와 같은 방법으로 설정한 state값을 가져올 수 있다.
<p>You clicked {count} times</p>
- state값 갱신 방법
<button onClick={() => setCount(count + 1)}>
Click me
</button>
- useState 의 state갱신함수는 값을 병합하는 것이 아니라 대체한다.
useEffect Hooks
-
useEffect는 함수 컴포넌트 내에서 이런 side effects를 수행할 수 있게 해준다
-
React class의 componentDidMount 나 componentDidUpdate, componentWillUnmount와 같은 목적으로 제공되지만, 하나의 API로 통합
-
Effect를 “해제”할 필요가 있다면, 해제하는 함수를 반환
-
이 반환되는 함수는 컴포넌트가 Unmount 될때, 그리고 재 렌더링이 일어나 effect를 재실행하기 전에 실행된다.
-
클래스의 하나의 로직에 여러개 함수를 써야한다는 복잡성때문에 탄생하게 되었다.
-
useState와 마찬가지로 컴포넌트 내에서 여러 개의 effect를 사용할 수 있다.
function FriendStatusWithCounter(props) {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
// ...
}
- Hooks를 사용하면 생명주기 메서드가 아닌 코드 로직에 따라 처리를 할 수 있다.
effect가 업데이트 시마다 실행되는 이유
- 클래스 컴포넌트에서 발생하는 버그를 해결하기 위해 effect 는 업데이트 시마다 실행된다.
- 클래스 일때 생명주기 메소드 예시
componentDidMount() {
ChatAPI.subscribeToFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}
componentWillUnmount() {
ChatAPI.unsubscribeFromFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}
-
컴포넌트가 화면에 표시되어있는 동안 friend prop 이 변한다면 컴포넌트는 온라인 상태로 잘못 표시하게 되고, 언마운트 될 때 다른 사용자가 해지되는 등의 충돌이 일어날 수 있다. 그래서 이를 막기 위해 componentDidUpdate 메소드를 사용하는데 이 또한 버그 중의 하나로 제대로 작동 되지 않는다.
-
useEffect는 업데이트를 다루기 때문에 이런 버그 들을 해결할 수 있다.
-
다음 effect를 적용하기 전 이전의 effect 는 정리 한다.
-
코드로 나타나면 다음과 같다
useEffect는 함수 컴포넌트 내에서 이런 side effects를 수행할 수 있게 해준다
React class의 componentDidMount 나 componentDidUpdate, componentWillUnmount와 같은 목적으로 제공되지만, 하나의 API로 통합
Effect를 “해제”할 필요가 있다면, 해제하는 함수를 반환
이 반환되는 함수는 컴포넌트가 Unmount 될때, 그리고 재 렌더링이 일어나 effect를 재실행하기 전에 실행된다.
클래스의 하나의 로직에 여러개 함수를 써야한다는 복잡성때문에 탄생하게 되었다.
useState와 마찬가지로 컴포넌트 내에서 여러 개의 effect를 사용할 수 있다.
function FriendStatusWithCounter(props) {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
// ...
}
componentDidMount() {
ChatAPI.subscribeToFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}
componentWillUnmount() {
ChatAPI.unsubscribeFromFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}
컴포넌트가 화면에 표시되어있는 동안 friend prop 이 변한다면 컴포넌트는 온라인 상태로 잘못 표시하게 되고, 언마운트 될 때 다른 사용자가 해지되는 등의 충돌이 일어날 수 있다. 그래서 이를 막기 위해 componentDidUpdate 메소드를 사용하는데 이 또한 버그 중의 하나로 제대로 작동 되지 않는다.
useEffect는 업데이트를 다루기 때문에 이런 버그 들을 해결할 수 있다.
다음 effect를 적용하기 전 이전의 effect 는 정리 한다.
코드로 나타나면 다음과 같다
성능 최적화
-
useEffect의 두번째 인수로 배열(useEffect 내에서 사용되는 데이터값)을 설정해주면 해당값이 변할때만 useEffect가 실행되게 함으로써 최적화를 꾀할 수 있다.
-
두번째 인자는 빌드 시 변환에 의해 자동으로 추가될 수도 있다.
-
다만 주의해야할 점은 이 최적화 방법을 사용할 때 컴포넌트 범위내에서 바뀌는 값들과 effect에 의해 사용되는 값들을 모두 포함해야한다는 것이다. 그렇지 않으면 이전 렌더링 값을 참고하게 된다.
-
두번째 인수에 빈배열을 넘기면 effect를 실행하고 정리하는 과정을 한번씩만 실행하게 된다. (어떤 값에도 의존하지 않으며 재실행될 필요가 없음을 명시하는 것이다).
빈 배열을 넘기게 되면 effect 안의 prop 과 state는 초깃값을 유지한다. -
리액트는 브라우저가 다 그려질때까지 useEffect의 실행을 지연한다.
-
eslint-plugin-react-hooks
를 설치하여서exhustive-dpes
규칙을 설정하면 의존성이 바르게 되지 않을때 경고해주게 된다.설치방법
$ npm install eslint-plugin-react-hooks --save-dev // ESLint 설정 파일 { "plugins": [ // ... "react-hooks" ], "rules": { // ... "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies } }
Hooks 사용 규칙
-
최상위(at the top level)에서만 Hook을 호출 (반복문, 조건문, 중첩 함수 내에서 훅을 실행하면 안된다)
-
컴포넌트 내에서만 훅을 호출한다.
-
직접 작성한 커스텀 훅 내에서는 훅을 호출할 수 있다.
-
리액트는 어떻게 특정 stater가 어떤 useState 호출에 해당하는지 알 수 있을까?
리액트가 호출되는 순서에 의존한다. 훅의 호출 순서는 같기 때문에 올바르게 동작한다. 그러나 만약 조건문 같은 경우로 훅이 건너뛰어진다면 리액트는 훅 호출에서 무엇을 반환할지 모르게 된다. 이는 버그를 발생시킨다. 조건부로 effect를 실행시키고 싶다면 useEffect내부에서 조건문을 설정해야 한다.
나만의 Hooks, Custom Hooks 작성
- 전통적인 방법이 두 가지 있었는데, higher-order components와 render props
- custom Hooks의 예시 (useFriendStatus훅)
import React, { useState, useEffect } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
useEffect(() => {
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
- 커스텀 훅을 만들면 여러 컴포넌트에서 재사용 가능하다
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
- 각 컴포넌트의 state는 완전히 독립적이다. Hook은 state 그 자체가 아니라, 상태 관련 로직을 재사용하는 방법이다.
- 심지어는 한 컴포넌트 안에서 같은 custom Hook을 두 번 쓸 수도 있다.
- 폼 핸들링, 애니메이션, 선언적 구독(declarative subscriptions), 타이머 등 많은 경우에 custom Hook을 사용할 수 있다
Author And Source
이 문제에 관하여(201008_TIL), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@oh_ji_0/201008TIL
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
최상위(at the top level)에서만 Hook을 호출 (반복문, 조건문, 중첩 함수 내에서 훅을 실행하면 안된다)
컴포넌트 내에서만 훅을 호출한다.
직접 작성한 커스텀 훅 내에서는 훅을 호출할 수 있다.
리액트는 어떻게 특정 stater가 어떤 useState 호출에 해당하는지 알 수 있을까?
리액트가 호출되는 순서에 의존한다. 훅의 호출 순서는 같기 때문에 올바르게 동작한다. 그러나 만약 조건문 같은 경우로 훅이 건너뛰어진다면 리액트는 훅 호출에서 무엇을 반환할지 모르게 된다. 이는 버그를 발생시킨다. 조건부로 effect를 실행시키고 싶다면 useEffect내부에서 조건문을 설정해야 한다.
- 전통적인 방법이 두 가지 있었는데, higher-order components와 render props
- custom Hooks의 예시 (useFriendStatus훅)
import React, { useState, useEffect } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
useEffect(() => {
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
- 커스텀 훅을 만들면 여러 컴포넌트에서 재사용 가능하다
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
- 각 컴포넌트의 state는 완전히 독립적이다. Hook은 state 그 자체가 아니라, 상태 관련 로직을 재사용하는 방법이다.
- 심지어는 한 컴포넌트 안에서 같은 custom Hook을 두 번 쓸 수도 있다.
- 폼 핸들링, 애니메이션, 선언적 구독(declarative subscriptions), 타이머 등 많은 경우에 custom Hook을 사용할 수 있다
Author And Source
이 문제에 관하여(201008_TIL), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@oh_ji_0/201008TIL저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)