React 데이터 흐름
React로 앱을 만들 때, 컴포넌트는 각각의 기능들을 만든 다음 조립하는 방식인 상향식(bottom-up)으로 만든다.
부모 컴포넌트에서 자식 컴포넌트로 props를 이용하여 전달인자(argument)처럼 데이터를 내려줄 수 있다.
이것은 데이터의 흐름이 햐향식(Top-down) 이라는 것을 의미한다.
이 원칙은 매우 중요한데, 단방향 데이터 흐름(one-way data flow)이라는 키워드가 React를 대표하는 키워드중 하나일 정도다.
두 개 이상의 컴포넌트에서 같은 상태를 공유해야 하는 경우 그 컴포넌트들의 공통 부모(조상) 컴포넌트를 찾아 상태를 지정해주고 상태를 props로 하위 컴포넌트에게 전달하면 된다.
그런데 이렇게 설정하고 보니 마치 자식 컴포넌트가 부모 컴포넌트의 데이터에 영향을 주는 역방향 데이터 흐름이 나타나는 것 처럼 보인다. 이것을 해결하기 위해 React는 상태 끌어올리기(Lifting State Up)을 제시한다.
상위 컴포넌트의 '상태를 변경하는 함수' 자체를 props로 하위 컴포넌트에 전달하고, 이 함수를 하위 컴포넌트가 실행한다.
이것을 상태 끌어올리기라고 한다. 이 방식은 단방향 데이터 흐름을 해치지 않는다.
Effect Hook
Side effect
함수 내 코드가 함수 외부에 영향을 끼치는 경우 해당 함수는 Side Effect가 있다고 이야기한다. React에서는 컴포넌트 내에서 fetch를 사용해 API 정보를 가져오거나 이벤트를 활용해 DOM 직접 조작할 때 Side Effect가 발생했다고 한다.
let foo = 'hello';
function bar() {
foo = 'world';
}
bar(); // bar는 Side Effect를 발생시킵니다!
Pure function(순수 함수)
순수 함수란, 오직 함수의 입력만이 함수의 결과에 영향을 주는 함수를 의미한다.
또한 순수 함수는, 입력으로 전달된 값을 수정하지 않는다.
function upper(str) {
return str.toUpperCase(); // toUpperCase 메소드는 원본을 수정하지 않는다 (Immutable)
}
upper('hello') // 'HELLO'
React의 함수 컴포넌트는 Side Effect가 없는 순수 함수로 작동한다.
하지만 보통 React 애플리케이션을 작성할 때에는, AJAX 요청이 필요하거나, LocalStorage 또는 타이머와 같은 React와 상관없는 API를 사용하는 경우 Side effect가 발생할 수 있다.
React는 Side Effect를 다루기 위한 Hook인 Effect Hook을 제공한다.
UseEffect
useEffect는 컴포넌트 내에서 Side effect를 실행할 수 있게 하는 Hook 이다.
useEffect의 첫 번째 인자로 함수를 넣어준다. 이 함수 내에서 side effect를 실행하면 된다.
useEffect(() => {
console.log("Hello", count);
});
매번 새롭게 컴포넌트가 렌더링 될 때 Effect Hook이 실행된다.
useEffect의 두 번째 인자로 배열을 넣을 수 있다. 이 배열은 조건을 담고 있는데 여기서 조건은 boolean 형태의 표현식이 아닌, 어떤 값의 변경이 일어날 때를 의미한다. 이 배열을 특별히 종속성 배열(dependency array)이라고 부른다.
종속성 배열에 담긴 값의 변화가 일어날 때 마다 effect 효과가 나타난다.
useEffect(() => {
console.log("Hello", count);
}, [count]);
// count 값이 변할때마다 effect 효과가 나타난다.
두번째 인자로 빈 배열을 넣으면 처음 렌더링될 때 한 번만 실행된다.
useEffect(() => {
console.log("Hello");
}, []);
// 처음 렌더링 될때 한 번만 실행된다.
두번째 인자를 생략하면 렌더링 될 때 마다 effect가 실행된다.
useEffect(() => {
console.log("Hello");
});
Ajax 요청
컴포넌트 내에서 Ajax 요청을 할 때 useEffect를 활용할 수 있다.
useEffect(() => {
fetch(`http://서버주소/proverbs?q=${filter}`)
.then(resp => resp.json())
.then(result => {
setStates(result);
});
}, [filter]);
filter 값이 바뀔 때 마다 서버에 데이터를 요청하여 알맞는 데이터를 받아 setStates함수를 이용해 states 변수에 담는다.
데이터 로딩이 오래걸릴 수 있기 때문에 로딩 화면을 띄워줘야 하는데, 그럴 때는 useEffect 내부에 로딩 state값을 바꿔주는 함수를 넣어주면 로딩중일때는 로딩화면을 렌더링하고 로딩이 다 되면 로딩 완료 화면을 보여줄 수 있다.
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setIsLoading(true);
fetch(`http://서버주소/proverbs?q=${filter}`)
.then(resp => resp.json())
.then(result => {
setStates(result);
setIsLoading(false); // 로딩완료되면 isLoading을 false로 바꿔준다.
});
}, [filter]);
// 생략, LoadingIndicator 컴포넌트는 별도로 구현했음을 가정합니다
return {isLoading ? <LoadingIndicator /> : <div>로딩 완료 화면</div>}
'코드스테이츠' 카테고리의 다른 글
2/6 일일정리 CORS, node server 실습 (0) | 2023.02.06 |
---|---|
2/3 일일정리 StatesAirline Client (0) | 2023.02.03 |
2/1 일일정리 HTTP 요청 실습 (0) | 2023.02.01 |
1/31 일일정리 REST API (0) | 2023.01.31 |
1/30 일일정리(2) HTTP/네트워크 기초 (0) | 2023.01.30 |
댓글