[React] Effect Hook

Eunji Lee·2022년 12월 6일
0

[TIL] Front-end

목록 보기
19/36
post-thumbnail

React 컴포넌트 외부에서 데이터를 처리하고 받아오는 과정

Side Effect

Side Effect(부수효과)

의미

  • 함수 내부의 구현이 함수 외부에 영향을 끼칠 때
  • 순수함수의 출력값에 영향을 미치는 작업
  • Side Effect로 인해 함수의 결과를 예측할 수 없음
    → 프로젝트나 소프트웨어의 유지 및 보수를 위해 Side Effect를 최소화하거나 함수로 따로 분리하기

예제

  • 전역변수인 foo가 함수 bar가 호출됨에 따라 수정
let foo = 'hello';

function bar() {
	foo = 'world';
}

bar();
console.log(foo); //'world' 출력
  • 변수c의 값에 따라 함수 sum의 리턴값이 달라짐
let c = 12;
function sum(a, b){
	return a + b + c
}
  • 함수 sum 안에 있는 변수 c는 함수 sum 밖에 있는 변수 c를 의미함
    → 함수 내부의 결과가 함수 밖에 영향을 줌
let c = 12;
function sum(a, b){
	c = a * b;
	return a + b;
}
  • 함수 sum의 계산이 obj에 영향을 미침
const obj = {value: 12};
function sum(obj, num){
	obj.value += num;
}
  • cf. 함수 sum의 연산 결과 새로운 객체 리턴하기 때문에 sum의 결과가 obj 에 영향을 주지 않음 → 순수함수
const obj = {value: 12};
function sum(obj, num){
	return {value: obj.value + num};
}

Pure Function(순수 함수)

  • 오직 함수의 입력만이 함수의 결과에 영향을 주는 함수
  • 함수의 외부 상태를 변경하지 않음
  • 전달인자가 주어졌을 때 항상 똑같은 값이 리턴되는 것을 보장함 → 예측 가능한 함수
  • 예시
let word = 'hello';
function upper(str) {
  return str.toUpperCase(); // toUpperCase 메소드는 원본을 수정하지 않음 (Immutable)
}

console.log(upper(word)); //'HELLO'
console.log(word); //'hello'

React에서 Pure Function과 Side Effect

Pure Function의 경우

  • props가 입력으로, JSX Element가 출력되는 경우
function SingleTweet({ writer, body, createdAt }) {
	return (
		<div>
			<div>{writer}</div>
			<div>{createdAt}</div>
			<div>{body}</div>
		</div>
	)
		

Side Effect의 경우

  • AJAX 요청이 필요할 때
    • 서버에 네트워크 요청을 보내면 이로 인해 서버의 데이터가 변경될 수 있음
      →Ajax 요청은 외부 상태를 바꿈
  • React와 상관없는 API를 사용하는 경우
    • fetch API, localStorage, setTimeout 사용 등



Effect Hook 기본

  • useEffect(): Hook API 중에 하나로, 컴포넌트 내에서 Side effect를 실행함
  • useEffect(함수) 실행시 함수 실행 조건
    • 새롭게 컴포넌트가 렌더링될 때
      → 렌더링이 무한 반복될 수 있기 때문에 조건부 사용을 더 권장
      • 컴포넌트 생성 후 처음 화면에 렌더링
      • 컴포넌트에 새로운 props가 전달되며 렌더링
      • 컴포넌트에 state가 바뀌며 렌더링
  • 주의사항
    • 최상위에서만 Hook 호출하기 → 컴포넌트가 렌더링 될 때마다 항상 동일한 순서로 Hook이 호출될 것을 보장하기 위해
    • React 함수 내에서 Hook 호출하기
  • 예시
    • 컴포넌트가 렌더링될 때마다 함수 실행
useEffect(() => {
	console.log(몇 번 호출될까요?)
})



Effect Hook 조건부 실행

  • useEffect(함수, [종속성1, 종속성2, ...])
    • 배열 내의 종속성1, 또는 종속성2의 이 변할 때만, 첫 번째 인자의 함수가 실행
  • 예시
    • 컴포넌트가 처음 렌더링된 후 함수 실행
      • 처음 단 한 번, 외부 API를 통해 리소스를 받아오고 더 이상 API 호출이 필요하지 않을 때 사용
    useEffect(() => {
        console.log(몇 번 호출될까요?)
    },[])
    • dep이 업데이트 될 때마다 함수 실행
      • 처음 컴포넌트가 렌더링 될 때 실행되고, 종속성 배열이 업데이트 될 때마다 실행됨
    useEffect(() => {
        console.log(몇 번 호출될까요?)
    },[dep])



컴포넌트 내에서의 Ajax 요청

목록 내 필터링 구현하기

  • 컴포넌트 내에서 필터링

    • 맨처음에 한 번만 외부 API에서 전체 목록 데이터를 불러오고, filter 함수를 사용해서 목록을 검색어로 filter 하는 방법
  • 컴포넌트 외부에서 필터링

    • 컴포넌트 외부로 API 요청을 할 때, 필터링 한 결과를 받아오는 방법 (서버에 매번 검색어와 함께 요청하는 경우의 대부분)
  • 장점 비교

    구분장점
    컴포넌트 내부 처리HTTP 요청의 빈도를 줄임
    컴포넌트 외부 처리클라이언트가 필터링 구현을 생각하지 않아도 됨

fetch API로 AJAX 요청 보내기

  • 예제
useEffect(() => {
  fetch(`http://서버주소/proverbs?q=${filter}`)
    .then(resp => resp.json())
    .then(result => {
      setProverbs(result);
    });
}, [filter]);

로딩 화면(loading indicator) 구현하기

  • 외부 API 접속이 느릴 경우 대비하기
    • 상태 처리하기
const [isLoading, setIsLoading] = useState(true);
// 생략, LoadingIndicator 컴포넌트는 별도로 구현했음을 가정
return {isLoading ? <LoadingIndicator /> : <div>로딩 완료 화면</div>}
  • fetch 요청 전후로 setIsLoading 설정하기
useEffect(() => {
  setIsLoading(true); //추가됨
  fetch(`http://서버주소/proverbs?q=${filter}`)
    .then(resp => resp.json())
    .then(result => {
      setProverbs(result);
      setIsLoading(false); //추가됨
    });
}, [filter]);

0개의 댓글