🔥 학습목표
- React 데이터 흐름인 단방향 데이터 흐름에 대해 이해한다.
- 어떤 컴포넌트에 state가 위치해야 하는지 판단할 수 있다.
- State 끌어올리기의 개념을 이해한다.
- 리액트를 다루는 기술 3.4절 state를 학습한다.
- 리액트를 다루는 기술 7장 컴포넌트의 라이프사이클에 대해 학습한다.
컴포넌트는 props
를 이용해 컴포넌트 바깥에서 데이터를 전달인자(arguments)처럼 받을 수 있다.
이때 데이터는 위에서 아래로, 즉 부모→자식으로 데이터를 전달하는데, 이를 단방향 데이터 흐름이라 한다.
Twitter 메인 화면을 만든다고 가정하였을 때, 트윗 목록을 보여주는 컴포넌트를 Tweets
라고 하고,
각각의 낱개 트윗들을 SingleTweet
컴포넌트로 구현한다고 해보자.
트윗 목록은 여러 개의 SingleTweet
컴포넌트로 나타낸다. 그러기 위해선 Tweets
에서 각각의 트윗 데이터를 SingleTweet
컴포넌트에 props
로 전달해야 한다.
이때 Tweet
컴포넌트가 부모, SingleTweet
컴포넌트가 자식이 된다.
state를 결정하는 조건은 다음 세 가지를 확인하면 된다.
그렇다면 state가 아니다!!
하나의 state를 기반으로 두 컴포넌트가 영향을 받는다면 공통 소유 컴포넌트를 찾아야 한다.
즉, 두 개의 자식 컴포넌트가 하나의 상태에 접근하고자 할 때는 두 자식의 공통 부모 컴포넌트에 상태를 위치해야 한다.
Twitter 예시에서, "전체 트윗 목록" state는 트윗 목록을 보여주는 컴포넌트인 Tweets
에서 필요로 하는 데이터다.
그런데 새 트윗을 작성하는 경우 NewTweetForm
컴포넌트에서 새로운 트윗 객체를 추가할 수 있어야 한다.
그렇다면 두 컴포넌트의 부모를 찾아 그곳에 "전체 트윗 목록" state를 관리해야 한다. 바로 최상단 부모인 Twittler
컴포넌트다.
방금 전까진 하향식 데이터 흐름이라 해놓고 갑자기 역방향...?
NewTweetForm
컴포넌트에서 트윗을 작성하면, 부모 컴포넌트 Twittler
의 상태를 바꾸어야 한다.
이를 해결하는 방법으로는 바로 state 끌어올리기가 있다.
상태를 변경시키는 함수
setState
를 자식 컴포넌트에props
로 전달하여, 부모에서 관리하는 상태를 자식에서 변경시킨다.
함수 내에서 어떤 구현이 함수 외부에 영향을 끼치는 경우
let foo = 'hello';
function bar() {
foo = 'world';
}
bar(); // bar는 Side Effect를 발생시킨다
React에서는 컴포넌트 내에서 fetch를 사용해 API 정보를 가져오거나, 이벤트를 활용해 DOM을 직접 조작할 때 Side Effect가 발생했다고 말한다.
아래 에어비앤비 홈페이지를 예시로 들어보자.
위 검색창 컴포넌트에서 condition
이라는 state
를 조작해 옵션 검색을 수행한다면,
검색창 컴포넌트로 인해 숙소 목록을 보여주는 컴포넌트의 내용이 바뀌게 된다.
오직 함수의 입력만이 함수의 결과에 영향을 주는 함수. 함수의 입력이 아닌 다른 값이 함수의 결과에 영향을 미치는 경우 순수함수라 부를 수 없다.
그냥 이 두 가지 조건만 지키면 순수함수다.
🌠 Math.random()은 순수 함수가 아닙니다. 왜일까?
└▶ 늘 같은 입력값을 받고, 늘 같은 결과값을 리턴한다는 조건을 위반한다. 매번 랜덤한 값을 반환하기 때문이다.
🌠 어떤 함수가 fetch API를 이용해 AJAX 요청을 한다고 가정해 보자. 이 함수는 순수 함수가 아니다. 왜일까?
└▶ 네트워크 상황 및 서버 상태에 따라 응답 코드가 달라지므로 예측이 불가능하다.
React의 함수 컴포넌트는 props가 입력으로, JSX Element가 출력으로 나간다.
그 어떤 사이드 이펙트도 없으며, 순수 함수로 작동한다.
function Component(props){
return<div>
<h1>함수 컴포넌트</h1>
</div>
}
하지만 웹앱을 개발하다보면 AJAX 요청/LocalStorage/타이머 같은 React와 상관 없는 API를 사용하게 된다.
이는 React 입장에서는 전부 Side Effect이다.
이러한 사이드 이펙트를 다루기 위해 React는 Effect Hook을 제공한다.
컴포넌트 내에서 Side effect를 실행할 수 있게 하는 Hook
어떤 값의 변경이 일어날 때 실행되는 effect 함수
useEffect(함수, [종속성1, 종속성2, ...])
위와 같이 작성하면 [종속성1, 종속성2, ...]
값이 변경될 때마다 effect 함수가 실행된다.
단, 업데이트 뿐 아니라 마운트 될 때도 실행되기 때문에 오직 업데이트가 될 때만 실행시키고 싶다면 다음 코드를 작성한다.
const mounted = useRef(false);
useEffect(() => {
if (!mounted.current) {
mounted.current = true;
} else {
console.log("업데이트 될 때마다 실행");
}
}, [종속성]);
단 한 번만 실행되는 effect
useEffect(함수, [])
위와 같이 두 번째 인자에 빈 배열을 담으면 컴포넌트가 처음 생성될 때에만 effect 함수가 실행된다.
대표적으로 처음 단 한 번, 외부 API를 통해 리소스를 받아오고 더이상 API 호출이 필요하지 않을 때 사용한다.
주로 공식적으로 아래와 같은 두 가지 방법으로 API를 불러온다. axios를 더 많이 쓰는 편이다. 그대로 기억해두어도 좋다.
useEffect(()=>{
// fetch
fetch(url)
.then((res) => res.json)
.then((data) => setState(data));
// axios
axios.get(url).then(res => {
const {data} = res;
setState(data);
})
}, []);
두 번째 인자가 없는 경우
useEffect(함수)
위에서 설명한 <실행되는 때>, 그러니까 컴포넌트가 처음 생성되거나, props가 업데이트 되거나, 상태가 업데이트 될 때 실행된다.