** 본 정리는 실전 리액트 프로그래밍(저자 : 이재승) 으로 부터 작성하였습니다 **

 

리액트 훅은 기존에 리액트가 갖고 있던 여러 가지 문제를 해결해 준다.

함수형 컴포넌트는 리액트 팀에서도 적극적으로 기능 개발에 많은 시간을 투자하고 있기 때문에

당장 클래스 컴포넌트로 구현한 프로젝트가 아니라면 시작할 때 함수형 컴포넌트로 대체하는 것이 좋다.

 

리액트 훅?

훅이란 함수형 컴포넌트에서도 클래스형 컴포넌트의 기능을 사용할 수 있게 하는 기능이다.

훅을 통해서 함수형 컴포넌트에서도 컴포넌트의 상탯값을 관리할 수 있고, 생명주기 함수를 이용할 수 있다.

 

훅을 사용하면 재사용 가능한 로직을 쉽게 만들 수 있으며, 

클래스형 컴포넌트와는 다르게 중복된 코드가 서로 다른 메서드에 들어가지 않는다.

 

useState 훅

useState 훅은 컴포넌트의 상탯값을 관리하는데 사용된다.

import React, { useState } from 'react';

function component({props}){
	const [name, setName] = useState('jh0956');
    return(
    	<div>
        	<div>{`name is ${name}`}</div>
            <input type="text" value={name} onChange={e=>setName(e.target.value)} />
        </div>
    )
}

[name, setName] 으로 선언하는 방식은 1개의 상태값을 사용하는 단순 형태이다.

useState('jh0956') 은 name의 기본값을 'jh0956'으로 지정한다는 초기화이다.

여기서 name은 상탯값의 이름이 되고, setName은 name이라는 상탯값을 변경하기 위한 함수이다.

 

또한 위의 방법으로 여러개의 useState 훅을 사용할 수도 있다.

하지만 좀더 간단하게 useState 훅 1개로 여러개의 useState 훅을 사용할 수도 있다.

import React, { useState } from 'react';

function component({props}){
	const [state, setState] = useState({
	name : 'jh0965',
    age : 25
    });
    
    return(
    	<div>
        	<div>{`name is ${state.name}}</div>
			<div>{`age is ${state.age}}</div>
            <input
            	type="text"
                value={state.name}
                onChange={e => setState({...state, name : e.target.value})} />
            ...
        </div>
    )
}

배열 비구조화 방식에서 state라는 변수는 '객체'가 되고 setState는 state 객체의 각 상태값의 변경을 위한 함수가 된다.

 

위 코드에서 onChange에서 setState를 호출하게 되는데

useState의 방식은 현재 받는 매개인자를 원래 상태값에 덮어버리는

즉 원래 상태값은 전부 지워버리고 받은 매개인자를 추가하는 방식이다.

 

그래서 전개연산을 통해 ...state의 기존 상태값을 주고, 그 중 name의 상태값만 변경하도록 코드해야한다.

 

생명주기 함수 useEffect

클래스형 컴포넌트의 생명주기 메서드는 서로 연관성이 없는 여러 기능이 하나의 생명 주기 메서드에 섞이는 등의

여러가지 문제점이 있다. useEffect를 사용하면 비슷한 기능을 한곳으로 모을수 있어서 가독성이 좋아진다.

 

useEffect 사용법

import React, { useState, useEffect } from 'react';

function component({props}){
	const [count, setCnt] = useState(0);
    
    useEffect( () => {
    	document.title = `업데이트 횟수: ${count}`;
    });
    return <button onClick = { () => setCnt(count+1) }>increase</button>;
}

** useEffect 훅에 입력된 함수는 렌더링 결과가 실제 돔에 반영된 후 호출된다 **

따라서 document.title 을 변경하는 코드를 클래스형 컴포넌트의 componentDidMount와 componentDidUpdate 

양쪽 메서드에 추가하면 같은 기능을 하게 된다.

클래스형 컴포넌트에서는 서로 다른 로직이 하나의 생명주기 메서드에서 작성되었지만, useEffect 훅을 이용하면 하나의 로직을 위한 코드를 한 곳으로 모을 수 있다.

버튼을 클릭할 때마다 다시 렌더링되고, 렌더링이 끝나면 useEffect 훅에 입력된 함수가 호출된다.

 

API를 호출하는 기능: 함수형 컴포넌트로 작성하기

클래스형 컴포넌트의 생명 주기 메서드에는 API를 호출하는 코드가 자주 포함된다.

함수형 컴포넌트에서도 훅을 이용해서 다음과 같이 API를 호출할 수 있다.

import React, {useState,useEffect} from 'react';

function component({props}){
	const [user, setUser] = useState('');
    useEffect( () => {
    	getUserAPI(props).then(data => serUser(data));
    	}, [props] // here!
    );
    
    return(
    	<div>
        	{!user && <div> 사용자 정보를 가져오는 중... </div>}
            {user && (
            	<div>
                	<!-- name과 age는 API 통신의 결과로 받아온 데이터 -->
                	<p>{`name is ${user.name}`}</p>
                    <p>{`age is ${user.age}`}</p>
                </div>
        </div>
    )
}

useEffect 훅에서 API통신을 가정한 코드이며 useState로 받아온 데이터를 저장한다.

주석처리한 here 부분을 보자

 

useEffect 훅에 입력된 함수는 렌더링 될 때마다 호출되기 때문에 API 통신을 불필요하게 많이 하게 된다.

이를 방지하기 위해 useEffect 훅의 2번째 매개변수로 배열을 입력하면 배열의 값이 변경되는 경우에만 함수가 호출된다

그렇기 때문에 위의 코드는 배열 props가 변경되는 경우에만 API 통신을 하도록 설정한다.

 

만약 위 코드를 클래스형으로 작성했다면 componentDidMount와 componentDidUpdate 두 메서드에 모두 작성했을 것이다.  

 

useEffect 이벤트 처리 함수를 등록하고 해제하는 기능

클래스형 컴포넌트에서는 componentDidMount 에서 구독을 하고 componentWillUnMount에서 해제하는 방식이 일반적이다. 서로 다른 로직이 하나의 생명 주기 메서드에 추가되면서 코드는 복잡해지고 실수가 발생하기 쉽다.

useEffect 훅을 이용하면 이러한 등록과 해제 절차를 한 곳에서 관리할 수 있다.

 

import React, { useState, useEffect } from 'react';

function component(){
	const [width, setWidth] = useState(window.innerWidth);
    useEffect( () => {
    	const onResize = () => setWidth(window.innerWidth);
        window.addEventListener('resize', onResize);
        return () => { window.removeEventListener('resize', onResize};
    }, []); // here!!
    
    return <div> {`width is ${width}`} </div>
}

위 코드는 창 크기가 변경될 때마다 onResize 함수가 호출된다.

useEffect 훅의 첫 번째 매개변수에 등록된 함수가 또 다른 함수를 반환할 수 있다.

반환된 함수는 컴포넌트가 unMount 되거나 첫 번째 매개변수로 입력된 함수가 호출되기 직전에 호출된다.

따라서 첫 번째 매개변수로 입력된 함수가 반환한 함수는 프로그램이 비정상적으로 종료되지 않는다면 반드시 호출될 것이 보장된다.

 

주석 here을 보자

useEffect 훅의 2번째 매개변수에 빈 배열을 넣으면 컴포넌트가 Mount 될 때만 첫 번째 매개변수로 입력된 함수가 호출되고, 컴포넌트가 unMount 될때만 반환된 함수가 호출된다.

=> 즉 이 코드는 componentDidMount와 componentWillUnMount 메서드에서만 실행되는 것과 같은 맥락이다.

 

위에서 API 호출, 이벤트 리스너를 예로 들어 설명하였다.

그리고 다음처럼 코드별로 분리해서 useEffect를 작성할 수도 있다.

import React, { useState, useEffect } from 'react';

function component({props}){
	const [width, setWidth] = useState(window.innerWidth);
    const [user, setUser] = useState('');
    
    useEffect( () => {
    	getUserApi(props).then(data => setUSer(data));
    }, [props]);
    
    useEffect( () => {
    	const onResize = () => setWidth(window.innerWidth);
        window.addEventListener('resize', onResize);
        return () => { window.removeEventListener('resize', onResize};
    }, []);
    
    return ..
}

만약 클래스형 컴포넌트로 작성했다면, 서로 다른 여러 로직이 분리되어 있지 않아 가독성이 떨어짐을 알게 된다.

 

Custom Hook!

리액트가 제공하는 훅을 이용해서 custom 훅을 만들 수 있다.

그리고 커스텀 훅을 이용해서 또 다른 커스텀 훅을 만들 수도 있다.

훅을 직접 만들어서 사용하면 고차 컴포넌트와 렌더 속성값 패턴처럼 로직을 재사용할 수 있다.

* 커스텀 훅을 만들 때는 use로 시작하도록 변수명을 정하자.

 

위에서 창의 너비를 관리하는 이벤트 리스너 코드를 가지고 커스텀 훅을 만들어보자.

이름은 useWindowWidth

import React, { useState, useEffect } from 'react';

function useWindowWidth(){
	const [width, setWidth ] = useState(window.innerWidth);
    
    useEffect( () => {
		const onResize = () => setWidth(window.innerWidth);
        window.addEventListener('resize', onResize);
        return () => window.removeEventListener('resize', onResize);
	},[]);
    
    return width;
}

useWindowWidth 함수는 useState, useEffect로 만들어 졌으며

마지막에 width를 반환하는 커스텀 훅으로 코드되었다.

 

방금 만든 useWindowWidth 훅은 이렇게 사용할 수 있다.

import React, {useState} from 'react';
import { useWindowWidth } from './hooks';

function component(){
	const width = useWindowWidth();
    const [name, setName] = useState('');
    return(
    	<div>
        	<p>{`name is ${name}`}</p>
            <width < 600 && <br />}
            <input type='text' value={name} onChange={e => setName(e.target.value)}/>
        </div>
    )
}

 useWindowWidth를 사용하므로 창의 너비가 바뀔 때마다 새로운 창의 너비와 함께 재렌더링 된다.

 

 

 

 

 

 

'web > React' 카테고리의 다른 글

create-react-app 정리  (0) 2020.12.30
CSS 단위(responsive Units)  (0) 2020.09.16
fetch request 비동기통신  (0) 2020.09.01
React NodeJs express 연동  (0) 2020.09.01
바벨(babel)  (0) 2020.08.22

firestore를 사용하면 프로젝트 초기에 권한을 설정하게 되는데

대게 일반 권한으로 기간 1달용을 사용하는 경우가 있다.

 

그 때 파이어베이스 설정에서는 timestamp를 기준으로 설정되는데

기간이 지나버리면 Uncaught (in promise) FirebaseError: Missing or insufficient permissions.

이라는 에러가 발생한다.

 

CLoud firestore 의 규칙에서 timestamp를 주석처리해놓고

와 같이 작성해주면 된다.

'web' 카테고리의 다른 글

리액트 문법 필기  (0) 2020.09.11
html async , defer  (0) 2020.09.09
SPA - Single Page Application  (0) 2020.09.09
CSS  (0) 2020.09.08
강의내용  (0) 2020.09.05

본 내용은 실전 리액트 프로그래밍 (저자 : 이재승) 의 책을 읽으며 필요한 것들을 필기한 것입니다.

*저작권에 문제가 될 시 삭제하겠습니다.

 

필요한 것은 검색해서 찾아보자

 

Computed property names_______________________________________________________________

 

계산된 속성명(computed property names) => 객체의 속성명을 동적으로 결정하는 ES6+ 문법

function func(key, values){
	return { [key] : values }
}

계산된 속성명을 사용하면 다음과 같이 컴포넌트의 상탯값을 변경할 때 유용하게 사용할 수 있다.

state = {
	count1 = 0,
    count2 = 0,
    count3 = 0
}

onClick = index => {
	const key = `count${key}`;
    const value = this.state[key];
    this.setState({[key] : value+1});
}

 

전개 연산자________________________________________________________________________________

 

전개 연산자 : 배열이나 객체의 모든 속성을 풀어놓을 때 사용하는 문법으로, 매개변수가 많은 함수를 호출할 때 유용

 

 Math.max(1,3,5,7);
 // 위 코드처럼 입력하지 않는 이상
 // 원하는 변수들을 동적으로 매개변수로 전달할 수 없다.
 
 const number = [1,3,5,7];
 Math.max(...number);
 
 // number이라는 배열을 동적으로 매개변수로 전달하는 전개 연산자의 사용 예시

 

** 배열에서 전개연산자를 사용하면 그 순서가 유지된다.

 

** 객체 리터럴에서는 ES5까지는 중복 속성명을 사용시 에러가 발생했지만 ES6 부터는 허용된다.

 

배열, 객체 비구조화_______________________________________________________________________

const arr = [1,2];
const [a,b] = arr;
console.log(a); // 1
console.log(b); // 2

이런식으로 새로운 변수로 할당할 수도 있고, 다음 코드처럼 이미 존재하는 변수에 할당할 수도 있다.

let a,b;
[a,b] = [1,2];

보통 두 변수를 swap할때는 제 3의 변수를 사용하게 되는데,

비구조화를 이용하면 1줄의 코드로 해결할 수 있다.

let a = 1;
let b = 2;
[a,b] = [b,a];

특정 위치를 제외한 배열의 나머지 값들은 전개 연산자를 통해 쉽게 분리할 수 있다.

 const arr = [1,2,3];
 const [first, ...arr2] = arr;
 console.log(first); // 1
 console.log(arr2); // [2,3]

 

배열의 경우 비구조화를 이용할 때 순서가 중요하지만 객체의 경우 속성명의 순서가 중요하지 않다.

const obj = { age:21, name : 'mike' };
const {age, name} == const {name, age} = obj;

또한 객체 비구조화의 경우 별칭을 사용할 수 있다.

** 객체 비구조화에서 계산된 속성명을 사용하는 경우 반드시 별칭을 입력해야 한다.

 

 

강화된 함수의 기능________________________________________________________________________

 

ES6부터 함수 매개변수에 기본값을 줄 수 있다.

function func(a = 1){
	console.log(a);
}

func(); // 1

위와 같이 인수 없이 함수를 호출하면 a에는 undefined가 입력되고,

기본값이 정의된 매개변수에 undefined를 입력하면 정의된 기본값 1이 a에 입력된다.

 

객체 비구조화처럼 기본값으로 함수 호출을 넣을 수 있고, 기본값이 필요한 경우에만 함수가 호출된다.

function getDefault(){
	console.log('인자가 없습니다');
}

function func(a = getDefault()){
	return a;
}

func(10); // 10
func(); // '인자가 없습니다'

 

나머지 매개변수는 입력된 인수 중에서 정의된 매개변수 개수만큼을 제외한 나머지를 배열로 만들어준다.

function func(a, ...arr){
	console.log({a, arr});
}

func(1,2,3); // { a:1, arr : [2,3] }

 

** ES6 부터는 함수를 화살표 => 를 이용해서 작성할 수 있다.

 

ES5부터 this의 전역환경 접근을 방지하기 위해 클로저(closure) 를 사용한다

 

클로저 : 함수가 생성되는 시점에 접근 가능했던 변수들을 생성 이후에도 계속해서 접근 할 수 있게 해주는 기능이다.

           접근 할 수 있는 변수는 그 함수를 감싸고 있는 상위 함수들의 매개 변수와 내부 변수들이다.

 

 

향상된 비동기 프로그래밍 1: Promise_____________________________________________________

Promise는 비동기 상태를 값으로 다룰 수 있는 객체이다.

promise를 사용하면 비동기 프로그래밍을 할 때 동기 프로그래밍 방식으로 코드를 작성할 수 있다.

promise가 보급되기 전에는 비동기 프로그래밍 코드인 콜백(call back) 패턴이 많이 쓰였다.

ES6부터는 promise가 javascript언어에 포함되었다.

 

사실 Promise를 사용하기 전에는 func(callback){ callback(data) } .. 식으로 사용했었는데

진짜 읽히지가 않는다. 너무 복잡해서

 

하지만 promise를 사용하면 원하는 순서대로 순차적 실행이 가능하기 때문에 너무 편해졌다.

 

func( .. ).then(data => { .. }).then(data => { .. }) 과 같은 코드가 promise를 사용한 코드이다.

사용방법을 알고 있기 때문에 적지는 않겠다.

 

Promise를 사용하면 데이터 캐싱이 가능하다.

'처리됨' 상태가 되면 그 상태를 유지하는 프로미스의 성질을 이용해서 데이터를 캐싱할 수 있게 되는데,

let cached;
getData => {
	cached = cached || requestData(); // requestData()의 return 값은 1이라 가정
    return cached;
}

getData().then( res => console.log(res) );
getData().then( res => console.log(res) );

첫번째 getData 함수를 호출할 때에만 requestData가 호출되고 

cached에는 1이라는 값과 함께 프로미스가 저장된다.

두번째 getData 함수를 호출하면 이미 프로미스가 저장되어 있기 때문에 재호출하지 않고도 cached를 얻을 수 있다.

 

** Promise를 병렬로 처리하기 **

 

만일 promise를 병렬로 처리하지 않고 다음과 같이 체인형식으로 처리한다면

requestData1() => {
	fetch() {...}
}

requestData2() => {
	fetch() {...}
}

requestData1()
.then(() => {
	requestData2() ...
})

requsetData1을 실행 후, promise가 반환되면 requestData2가 실행될 것이다.

 

작업 중에 비동기로 처리해야하는 경우가 굳이 순차적으로 발생할 필요가 없다면

위와 같은 코드는 시간손해를 보게 된다.

 

이때는 Promise.all을 이용해서 원하는 작업을 병렬로 처리할 수 있다.

Promise.all([requestData1(), requestData2()])
.then( ([res1, res2]) => console.log(res1, res2); );

Promise.all 은 requestData1과 requestData2 과 같은 입력된 모든 프로미스가 '처리됨' 상태가 되어야 

마찬가지로 '처리됨' 상태가 된다.

 

향상된 비동기 프로그래밍 2: async await________________________________________________

 

async await는 비동기 프로그래밍을 동기 프로그래밍처럼 작성할 수 있도록 함수에 추가된 기능이다.

promise가 javscript의 표준이 되고 2년 후인 ES7에 async await도 javascript 표준이 되었는데,

async await를 이용해서 비동기 코드를 작성하면 promise의 then 메서드를 호출하는 것보다 가독성이 좋아진다.

** 그렇다고 async await가 promise를 완전히 대체하는 것은 아니다.

** promise는 비동기 상태를 값으로 다룰 수 있기 때문에 async await보다 큰 개념에 속한다.

 

async await 함수는 반드시 promise를 반환한다.

promise는 객체로 존재하지만 async await는 함수에 적용되는 개념이다.

async function func() {
	return 1;
}

func().then(res => console.log(res)); // 1

async 기호를 이용해서 함수를 정의하면 async await function이 된다.

promise를 반환하기 때문에 위와 같이 then을 사용할 수 있다.

 

await 키워드는 다음과 같이 사용할 수 있다.

function requestData(value) {
	return new Promise(resolve => {
    	setTimeout( () => {
        	console.log('requestData : ', value);
            resolve(value);
        }, 1000),
    };
}

async function getData(){
	const res1 = await requestData(10);
    const res2 = await requestData(20);
    console.log(res1, res2);
    return [res1, res2];
}

getData();
==> requestData : 10
==> requestData : 20
==> 10 20

await 키워드를 사용하였기 때문에

res1이 실행되면, promise 객체를 받기 전까지 res2는 실행되지 않는다.

마찬가지로 res2가 promise 객체를 받기 전까지 console.log(res1, res2)는 실행되지 않는다.

 

비동기 함수간의 의존성이 높아질수록 promise 와 async await의 가독성 차이는 드러나게 된다.

그렇기 때문에 then catch를 사용하는데 편해지긴 했지만

async await를 연습하는 것이 간결한 코드를 작성하는데 더욱 도움이 될 수 있을 것이다!

 

** async await도 병렬로 실행가능하다.

단순하게 await 키워드를 나중에 사용하면 된다.

 

async function func() {
	const res1 = asyncfunc1();
    const res2 = asyncfunc2();
    const data1 = await res1;
    const data2 = await res2;
}

// 물론 Promise.all로도 사용가능하다

async function func(){
	const [data1, data2] = await Promise.all([asyncfunc1(), asyncfunc2()]);
}

 

제너레이터..는 아직 언제 쓰여야될지 감을 못잡겠다. 나중에 필요할 때 다시 읽어봐야겠다.

 

 

render____________________________________________________________________________________

리액트의 가장 기본적이면서도 가장 중요한 것이 컴포넌트는 상태값과 속성값을 관리하면서 UI를 관리해야 한다는 것

UI 데이터에는 상태값과 속성값이 있는데, UI 데이터가 변경되면 리액트가 렌더 함수를 이용해서 화면을 자동으로 갱신!

** 자식 컴포넌트는 부모 컴포넌트가 렌더링 될때 마다 같이 렌더링 되는게 default이다

 

* 만약 지정한 어떤 UI 데이터만 변경될 때 렌더링 되기를 원한다면 React.memo, React.PureComponent를 사용한다.

// memo 함수의 인자로 함수형 컴포넌트를 입력시
function Title(props){
	return <p>{props.title}</p>
}

export default React.memo(Title);


// PureComponent 를 확장해서 클래스형 컴포넌트를 만들면 memo와 같은 효과를 낼 수 있다. 
export default class Title extends React.PureComponent{
	render(
    	return 
    )
}

 

위는 title이라는 부모 컴포넌트로부터 받은 속성값이 변경될 때만 재렌더링 되게끔 한다.

지정해주지 않으면 title 값이 바뀌지 않아도 부모컴포넌트가 렌더링되면 Title도 렌더링된다.

 

 

 setState (비동기로 상태값 변경)

setState는 클래스형 컴포넌트에서 상태값을 변경할 때 호출하는 메서드로, 

setState 메서드가 호출되면 리액트는 '해당'컴포넌트를 다시 그리게 된다.

만약 변화된 상태값 중에 자식에게 물려주게 될 속성값이 있다면 자식 컴포넌트로 재렌더링 된다.

 

다음은 setState를 연속해서 2번 호출하는 코드이다

this.setState({count : this.state.count + 1});
this.setState({count : this.state.count + 1});

이 코드가 의도하는 바는 state의 count를 2 증가시키는 것이다

하지만 의도대로 동작하지 않고 1만 증가한다.

원인은 setState는 비동기로 동작하기 때문!

 

리액트는 효율적으로 렌더링하기 위해서 여러 개의 setState 메서드를 batch로 처리한다.

리액트가 setState 메서드를 동기로 처리하면 하나의 setState 메서드가 호출될 때마다 화면을 다시 그리기 때문에

성능 이슈가 발생할 수 있다.

 

위 코드를 원하는대로 2만큼 증가시키기 위해서 setState의 인수로 함수를 입력하여 해결할 수 있다.

this.setState(prevState => ({count : prevState.count + 1});
this.setState(prevState => ({count : prevState.count + 1});

setState 메서드로 입력된 함수는 자신이 호출되기 직전의 상탯값을 매개변수로 받는다.

앞의 코드에서 첫 번째 setState 호출이 변경한 상태값이 두 번째 setState 호출의 인수로 사용된다고 이해할 수 있다.

 

 

리액트 요소와 가상 돔 

리액트 요소는 리액트가 UI를 표현하는 수단이다.

리액트는 렌더링 성능을 위해 가상 돔을 활용한다.

빠른 렌더링을 위해서는 돔 변경을 최소화해야 한다.

그래서 리액트는 메모리에 가상 돔을 올려 놓고 이전과 이후의 가상 돔을 비교해서 변경된 부분만 실제 돔에 반영한다.

 

 

** 생명 주기 메서드 **

모든 컴포넌트는 3가지 단계를 거친다.

1. 초기화 단계

2. 업데이트 단계

3. 소멸 단계

 

각 단계에서는 몇 개의 메서드들이 정해진 순서대로 호출된다. 이를 생명 주기 메서드라고 한다.

 

 

- 초기화 단계

초기화 단계는 최초에 컴포넌트 객체가 생성될 때 '한 번' 수행된다.

constructor() -> static getDerivedStateFromProps() -> render() -> componentDidMount()

 

 

- 업데이트 단계

업데이트 단계는 초기화 단계와 소멸 단계 사이에서 반복해서 수행된다.

컴포넌트의 속성값 또는 상태값이 변경되면 업데이트 단계가 수행된다.

static getDerivedStateFromProps() -> shouldComponenetUpdate() -> render() ->

getSnapshotBeforeUpdate() -> componentDidUpdate()

 

 

- 소멸 단계

소멸 단계에서는 componentWillUnmount() 가 호출된다.

 

 

- 예외

3단계와는 별개로 렌더링 시 예외가 발생하면 다음과 같은 메서드가 호출된다.

static getDerivedStateFromError() -> componentDidCatch()

 

 

constructor 메서드

constructor 메서드의 구조는 다음과 같다

 

constructor(props)

 

props 매개변수는 컴포넌트의 기본 속성값이 적용된 상태로 호출된다.

constructor 메서드 내부에서 반드시 super() 함수를 호출해야 한다.

 

super 함수를 호출해야 React.Component 클래스의 constructor 메서드가 호출된다.

따라서 super 함수를 호출하지 않으면 컴포넌트가 제대로 동작하지 않는다.

 

* constructor 메서드 작성이 필요한 대표적인 예는 초기 속성값으로부터 상탯값을 만드는 경우이다 *

* 상탯값 state를 직접 할당하는 것은 constructor 메서드에서만 허용된다 *

* 지금은 클래스 필드(class field)를 사용하면 constructor 메서드를 사용하지 않고도 상탯값을 초기화할 수 있다 *

* constructor 메서드에서는 setState를 호출하지 말자(무시됨) *

 

static getDerivedStateFromProps 메서드

getDerivedStateFromProps 메서드는 속성값을 이용해서 새로운 상탯값을 만들 때 사용한다.

정적 메서드이기 때문에 this 객체에 접근할 수 없다. 반드시 상탯값과 속성값만을 이용해서 새로운 상태값을 만든다.

getDerivedStateFromProps 메서드는 주로 시간에 따라 변하는 속성값으로부터 상탯값을 계산하기 위해 추가됐다.

하지만 속성값 변화에 따른 추가적인 처리를 getDerivedStateFromProps 메서드에서만 할 수 있는 것은 아니다.

 

render 메서드

렌더 함수 내에서 setState를 호출하면 안된다.

렌더 함수의 반환값은 속성값과 상태값만으로 결정되어야 한다.

부수 효과(서버와 통신, 브라우저의 쿠키에 저장하기 등)를 발생시키면 안된다.

 

 

componentDidMount 메서드

componentDidMount 메서드는 render 메서드의 첫 번째 반환값이 실제 돔에 반영된 직후 호출된다.

따라서 render 메서드에서 반환한 리액트 요소가 돔에 반영되어야 알 수 있는 값을 얻을 수 있다.

 

componentDidMount 메서드가 호출될 때는 리액트 요소가 돔 요소로 만들어진 시점이기 때문에 

돔 요소에 접근할 수 있게 된다.

이 때 필요한 정보들을 통해서 setState를 호출하면 원하는 방향으로 렌더링 할 수 있다.

 

** componentDidMount 메서드는 API 호출을 통해 데이터를 가져올 때 적합하다.

그런데 위 설명에 API 호출은 constructor 에서 하지말라고 하였지만

사실 constructor가 componentDidMount 보다 먼저 호출되는건 명백하다.

이 때 promise 객체를 constructor에서 받아두고 componentDidMount 에서 사용하는 방법은 API 호출 응답 시간에

민감한 애플리케이션이라면 좋은 방법이 될 수 있다.

 

 

 

shouldComponentUpdate 메서드

shouldComponentUpdate 메서드는 '성능 최적화' 를 위해서 사용된다.

즉, 성능 이슈가 발생했을 때 메서드를 작성해도 늦지 않다고 한다.

 

shouldComponentUpdate(nextProps, nextState) 의 구조로 이루어져 있으며,

true, false를 반환하는데 default 값은 true이다.

메서드 내부에서 true 값을 반환하게 되면 render 메서드가 호출된다.

이점을 이용해서 굳이 렌더링 되지 않아도 될 부분을 중지시킴으로써 성능 최적화를 하는 것!

 

 

 

componentDidUpdate 메서드

componentDidUpdate 메서드는 업데이트 단계에서 마지막으로 호출되는데,

* 가상 돔이 실제 돔에 반영된 후 호출된다 *

* 즉 새로 반영된 실제 돔에서의 상탯값을 가장 빠르게 가져올 수 있는 메서드이다 *

componentDidUpdate 메서드는 속성값이나 상탯값이 변경된 경우 API 호출을 위해 사용되기도 한다.

 

 

componentWillUnmount 메서드

componentWillUnmount 메서드는 소멸 단계에서 유일하게 호출되는 메서드이다.

끝나지 않은 작업 (ex : addEventListener) 을 처리하기 위해 호출된다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'web' 카테고리의 다른 글

FirebaseError: Missing or insufficient permissions.  (0) 2020.09.14
html async , defer  (0) 2020.09.09
SPA - Single Page Application  (0) 2020.09.09
CSS  (0) 2020.09.08
강의내용  (0) 2020.09.05

보통 html을 작성할 떄

<script src = .. 문을 사용하여  javascript 코드를 이용하게 된다

 

일반적으로 html이 모두 파싱되어서 DOM 요소가 생성된 후에 js를 읽는 방식인

<body> 끝부분에 script를 선언하게 되는데

 

이역시 파싱이 끝나고 나서 js 파일을 서버로부터 받아서 요소들에 적용시키기 때문에

사용자 입장에서는 기다려야 한다는 단점이 발생하게 된다. 즉 느리다

 

script async src = ... 

script defer src = ...

 

이 두가지를 설명할테니 장단점을 알아본 후 위의 단점을 해결하는 방안을 찾아보자

 

Async?___________________________________________________________

 

async을 사용하게 되면

html 코드를 파싱하다가 script를 만나는 순간 js 파일을 fetching(서버로부터 가져옴) 하는 작업이 

병렬적으로 실행된다.

=> 병렬적으로 발생하는 fetching 작업이 종료되면

컴파일러는 파싱을 중단하고 fetching한 js 코드를 executing(실행, 적용) 하는 과정을 거치게 된다.

 

분명 async을 사용하지 않는 것 보다 사용하는 것이 사용자측면에서 좀더 빠른 서비스를 경험하게 된다.

 

단점은?

애초에 async을 body 내에서 사용하는 것은 별반 차이가 없다

즉 head 내에서 사용하게 되는데

이 경우 executing 하는 과정에서 만약 컴파일러가 아직 js 에 선언된 변수(querySelector 등)를

읽지 못했다면 body 내에서 선언했더라도 사용할 수 없게 되어 에러가 발생하게 된다.

 

 

defer?______________________________________________________

 

defer은 async보다 좀더 좋은 동작을 수행한다.

async이 병렬적으로 끝난 fetching 마다 executing을 실행했다면,

defer은 fetching이 끝났어도 executing을 실행하지 않는다.

==> page parsing이 끝난 직후에 fetching이 끝난 모든 js를 executing 하게 된다.

 

사용자측면에서는 defer을 사용할 떄 더욱 빠른 서비스를 경험할 수 있게 된다. 

'web' 카테고리의 다른 글

FirebaseError: Missing or insufficient permissions.  (0) 2020.09.14
리액트 문법 필기  (0) 2020.09.11
SPA - Single Page Application  (0) 2020.09.09
CSS  (0) 2020.09.08
강의내용  (0) 2020.09.05

+ Recent posts