라이프사이클 React Hook useEffect useRef Promise.all

hyeseon han·2021년 10월 7일
0

컴포넌트 생명주기(Life Cycle)

React 컴포넌트는 생명 주기가 있다. 생명주기 메서드는 컴포넌트가 브라우저상에 나타나고, 업데이트되고, 사라지게 될 때 호출되는 메서드들 입니다. 추가적으로 컴포넌트에서 에러가 났을 때 호출되는 메서드도 있습니다.
생명주기 메서드는 클래스형 컴포넌트에서만 활용하고, 함수형 컴포넌트는 Hook을 사용한다.

  1. 그리기
    render

  2. 그리고 난 뒤
    componentDidMount

  3. 그리고 난 뒤 변경됐을 때
    componentDidUpdate

  4. 그리고 난 뒤 사라질 때
    componentWillUnmount

    참고

클래스형 컴포넌트 생명주기

import { Component, createRef } from "react";
import Router from "next/router";

interface IState {
  count: number;
}

export default class ClassComponentLifecyclePage extends Component {
  inputRef = createRef<HTMLInputElement>();

  state = {
    count: 0,
  };

  // 컴포넌트가 그려지고 난 이후에
  componentDidMount = () => {
    console.log("컴포넌트 마운트 완료");
    this.inputRef.current.focus();
  };

  componentDidUpdate = () => {
    console.log("컴포넌트 수정 완료");
  };

  // 컴포넌트 사라질 때  페이지 이동하면 잘가요~~ 왜 필요? 채팅 방에서 나가는 경우 알림
  componentWillUnmount = () => {
    console.log("잘가요~~");
  };

  onClickCount = () => {
    this.setState((prev: IState) => ({
      count: prev.count + 1, // prev 가 가지고있는 count
    }));
  };

  onClickMove = () => {
    Router.push("/");
  };

  render() {
    return (
      <>
        현재카운트: {this.state.count}
        <button onClick={this.onClickCount}>카운트 증가!!</button>
        <button onClick={this.onClickMove}>페이지 이동하기</button>
        <input type="text" ref={this.inputRef} />
      </>
    );
  }
}

함수형 컴포넌트 생명주기

import { useEffect, useState, useRef } from "react";
import { useRouter } from "next/router";

export default function FunctionalComponentLifecycle() {
  const router = useRouter();
  const [count, setCount] = useState(0);

  // 위에를 이렇게 쓸 수도 있음
  // const [state, setState] = useState({
  //     count: 0
  // })

  const inputRef = useRef<HTMLInputElement>();

  // componentDidMount 와 동일
  useEffect(() => {
    console.log("컴포넌트 마운트 완료!!");
    inputRef.current.focus();

    // componetWillUnmount 와 동일(사라지는 작업을 할 때는 이부분에서)
    return () => {
      console.log("잘가요~~");
    };
  }, []); // [ ] 의존성배열

  // componentDidUpdate 와 동일 ( 100% 일치하지는 않음. 처음에 한번 무조건 실행(console)되는 성격때문에)
  useEffect(() => {
    console.log("컴포넌트 수정 완료!!");
  });

  // setState와 useEffect
  //   useEffect(() => {
  //     setCount((prev) => prev + 1)
  //   }, [])

  // setState와 useEffect의 dependency-array
  //   useEffect(() => {
  //     setCount((prev) => prev + 1);
  //   }, [count]);

  function onClickCount() {
    setCount((prev) => prev + 1);
  }

  function onClickMove() {
    router.push("/"); // 아무페이지나 이동
  }

  return (
    <>
      현재카운트: {count}
      <button onClick={onClickCount}>카운트 증가!!</button>
      <button onClick={onClickMove}>페이지 이동</button>
      <input type="text" ref={inputRef} />
    </>
  );
}

React hooks

- useEffect

Hooks에서는 useEffect를 통해 Lifecycle을 관리한다.
useEffect는 클래스 생명주기 메소드에서 componentDidMountcomponentDidUpdate, componentWillUnmont 세 가지 역할을 한다.

useEffect는 컴포넌트가 그려진 이후에 실행되는 함수이다. 콜백 함수를 가지며, 의존성 배열(Dependency)이 있을 수도 있고 없을 수도 있다. 무조건 렌더링 후 한번 실행된다.

1. 의존성 배열(Dependency)이 없는 경우

 useEffect(() => {
    console.log("컴포넌트 수정 완료!!");
  });

어떤 값이 변화하면 그것을 인지하고 실행된다. 그래서 불필요한 실행이 많이 발생한다.

2. 의존성 배열(Dependency)이 있는 경우

  // componentDidMount 와 동일
  useEffect(() => {
    console.log("컴포넌트 마운트 완료!!");
    inputRef.current.focus();

    // componetWillUnmount 와 동일(사라지는 작업을 할 때는 이부분에서)
    return () => {
      console.log("잘가요~~");
    };
  }, []); // [ ] 의존성배열

빈 의존성 배열이 있으면, 렌더링 후 딱 단 한 번만 실행되고 다시는 실행되지 않는다.

3. 의존성 배열(Dependency) 안에 특정 변수 지정하는 경우

     useEffect(() => {
       setCount((prev) => prev + 1);
     }, [count]);

렌더링 후 한번 실행되고, 의존성 배열 안의 변수의 값이 변할 때 만 실행된다.

참고


- useRef

특정 태그를 조작하기 위해 선택할 때 사용하는 도구이다.
JavaScript 를 사용 할 때에는, 특정 DOM 을 선택해야 하는 상황에 getElementById, querySelector 같은 DOM Selector 함수를 사용해서 DOM 을 선택한다. react에서는 ref 를 사용해서 DOM을 선택한다.

useRefcurrent속성을 가지는 객체를 반환하는데, 인자로 넘어온 초기값을 current 속성에 할당한다. current 속성은 값을 변경해도 상태를 변경할 때처럼 렌더링되지 않는다.

예) input 태그해서 커서 깜빡깜박, 특정 엘리먼트의 크기/색상 변경, 스크로라 위치 가져오기 등..


  const inputRef = useRef<HTMLInputElement>();

  useEffect(() => {
    console.log("컴포넌트 마운트 완료!!");
    inputRef.current.focus();

    return () => {
      console.log("잘가요~~");
    };
  }, []); 
// useRef로 이미지 등록 구현하기
const inputRef = useRef<HTMLInputElement>(null);

useEffect(() => {
  inputRef.current?.focus();
}, []);

return <input type="password" ref={inputRef} />;
import { useRef } from 'react';

export default function Web() {
	const inputEl = useRef();

	const readImage = (input) => {
		// 인풋 태그에 파일이 있는 경우
		if (input.target.files && input.target.files[0]) {
	// FileReader 인스턴스 생성
	const reader = new FileReader();
	// reader가 이미지 읽도록 하기
        reader.readAsDataURL(input.target.files[0]);
	// 이미지가 로드가 된 경우
	reader.onload = (e) => {
		const previewImage =document.getElementById('image');
			previewImage.src = e.target.result;
				}
		}
	};

	const handleFileBtn = () => {
		inputEl.current.click();
	};

	return (
		<>
			<div>
				<img onClick={handleFileBtn} style={{ width: '500px' }} id="image" />
				<input
					hidden={true}
					ref={inputEl}
					id="fileTag"
					type="file"
					onChange={readImage}
				></input>
				<button onClick={handleFileBtn}>이미지 등록 버튼</button>
			</div>
		</>
	);
}

읽어보기
읽어보기

Promise.all

동기 요청을 한 번에 보내는 역할을 한다.

Promise
비동기 처리할 때 데이터를 주긴 줄게, 약속만 하는거. 아직 안줌. Promise를 동시에 받는 방법이 있음 ➤ Promise.all([배열])

//시간 재는거
const start = performance.now();
//이미지를 5개를 넣는 다고 가정. 업로드를 5번 해줘야함. async await 이라 순서대로 기다려야함. 총 5번 뮤테이션 너무 오래걸림. 동시에 올리는 방법을 해야함.=> Promise.all
const result1 = await uploadFile({variables: {file: myFile}}),
const result2 = await uploadFile({variables: {file: myFile}}),
const result3 = await uploadFile({variables: {file: myFile}}),
const result4 = await uploadFile({variables: {file: myFile}}),
const result5 = await uploadFile({variables: {file: myFile}});
const end = performance.now();
    // console.log(end - start);
async function onClickSubmit() {
  const start = performance.now();
  Promise.all([
     uploadFile({ variables: { file: myFile } }), 
     uploadFile({ variables: { file: myFile } }),
     uploadFile({ variables: { file: myFile } }), 
     uploadFile({ variables: { file: myFile } }),
     uploadFile({ variables: { file: myFile } }),
    ]);
// 5개 동시에 보내고 동시에 받고. => 5개 동시에 보내고 5개 다 받을 때까지 await    

0개의 댓글