state는 리액트 컴포넌트의 상태를 의미함.
쉽게 말하자면 리액트 컴포넌트의 변경 가능한 데이터를 state라고 부름. 사전에 정해진건 아니고 리액트 컴포넌트를 개발하는 각 개발자가 직접 정의해서 사용함.
중요한 점은 렌더링이나 데이터 흐름에 사용되는 값만 state에 포함 시켜야한다는 것임.
->state가변경될 경우 컴포넌트가 재렌더링 되기때문에 렌더링과 데이터흐름에 관련없는 값을 포함하면 컴포넌트가 다시 재렌더링되어 성능저하됨.
그냥 state는 자바스크립트의 객체라고 생각하면됨.
class LikeButton extends React.Component {
constructor(props) {
super(props)
this.state = {
liked: false
};
}
}
여기서 this.state부분이 나오는데 이 부분이 바로 현재 컴포넌트의 state를 정의하는 부분임.
위에같이 class컴포넌트의 경우 state를 constructor이라는 생성자에서 정의하고
함수컴포넌트에서는 state를 useState()라는 훅을 사용하여서 정의함.
//잘못된 사용법(state를 직접 수정하는것)
this.state = {
name: 'taeyoung'
};
//올바른 사용법(setState를 사용하여서 수정)
this.setState({
name: 'taeyoung'
});
이렇게 state를 직접 수정할순있지만 리액트에서 인식을 못 할 경우를 생각하여서 그냥 직접수정하지말고 setState를 사용하여서 수정해야됨.
리액트 컴포넌트도 사람같이 생명주기를 가지고있음.
그니까 리액트 컴포넌트가 생성되는 시점과 사라지는 시점이 정해져있다는 의미임.
출생 -> 인생 -> 사망
먼저 컴포넌트가 생성되는 시점인 출생시점이다 이 과정을 마운트라고 부르는데 이때 컴포넌트의 constructor(생성자)가 실행된다.
이 생성자에서는 컴포넌트의 state를 정의하게된다. 또한 컴포넌트가 렌더링되며 이후에 componentDidMount()함수가 호출이된다.
그 다음은 출생을 했으니 인생을 살아가겠지?
사람은 인생을 살아가는 동안 신체적, 정신적으로 변화를 겪잖아 그치? 이처럼 리액트 컴포넌트도 생애동안 변화를 겪으면서 여러번 렌더링됨.
이러한 과정을 업데이트되는 과정이라고 할수있음.
업데이트 과정에서는 컴포넌트의 props가 변경되거나 setState()함수 호출에 의해 state가 변경되거나 forceUpdate()라는 강제 업데이트 함수 호출로 인해 컴포넌트가 다시 렌더링됨.
그리고 렌더링 이후에 componentDidUpdate()함수가 호출됨.
그리고 마지막으로는 사망과정
사람은 누구나 나이를 먹고 죽잖아 ㅇㅈ?
리액트 컴포넌트 또한 이 과정을 거치게되는데 이 과정을 언마운트라고 부름.
그럼 컴포넌트는 언제 언마운트가 될까? 바로 상위 컴포넌트에서 현재 컴포넌트를 더 이상 화면에 표시하지 않게 될때 언마운트 된다고 볼 수 있음.
이때 언마운트 직전에 componentWillUnmount()함수가 호출됨.
이 생명주기에서 가장 중요한것은 컴포넌트가 계속 존재하는 것이 아니라 시간의 흐름에 따라 생성되고 업데이트되다가 사라진다는 것임.
프로그래밍에서 훅은 원래 존재하는 어떤 기능에 마치 갈고리를 거는 것처럼 끼어 들어가 같이 수행되는 것을 의미한다.
리액트에서의 훅도 마찬가지로 리액트의 state와 생명주기 기능에 갈고리를 걸어 원하는 시점에 정해진 함수를 실행되도록 만든것. 그리고 이때 실행되는 함수를 훅이라고 부르기로 정함!
이런 훅의 이름은 모두!! use로 시작됨!
훅이 수행하는 기능에 따라서 이름을 짓게 되었는데 각 기능을 사용하겠다는 의미로 use를 앞에 붙임.
뭐 대표적인 훅으로는 useState를 들수있다. state를 사용하기 위한 훅이고
코드를 보면서 이해해보자!
import React, {useState} from "react";
function Counter(props) {
var count = 0;
return (
<div>
<p>총 {count}번 클릭했습니다.</p>
<button onClick={() => count++}>
클릭
</button>
</div>
);
}
이건 Counter이라는 함수 컴포넌트이다 딱 보면 버튼 클릭하면 카운트 하나씩 증가시키고 현재 카운트 횟수를 보여주는 간단한 컴포넌트이다.
근데 만약에 이렇게 위해 코딩한거마냥해버리면 버튼 클릭하면 카운트 값이 증가는 되겠지만 재렌더링이 되지않기에 화면에 새로운 카운트 값이 표시가되지않는다. 따라서 이런 경우에는 state를 사용하여서 값이 바뀔때마다 재렌더링을 시켜주어야한다.
근데 class컴포넌트가 아닌 함수컴포넌트에는 이런 해당 기능이 따로 없기에 useState를 사용하여서 state를 선언하고 업데이트를 해야한다!
const[변수명, set함수명] = useState(초깃값);
useState()는 다음과 같이 사용이된다!
useState()를 호출할때에는 파라미터로 선언할 state의 초깃값이 들어간다.이렇게 초깃값을 넣어 useState()를 호출하면 리턴값으로 배열이 나온다 리턴된 배열에는 두가지 항목이있는데 첫 항목은 state로 선언된 변수이고 두번째 항목은 state의 set함수임.
import React, {useState} from "react";
function Counter(props) {
const[count, setCount] = useState(0);
return (
<div>
<p>총 {count}번 클릭했습니다.</p>
<button onClick={() => setCount(count + 1)}>
클릭
</button>
</div>
);
}
이렇게 useState()를 사용하여 count값을 state로 관리하는건데 이 코드에서 state의 변수명과 함수가 각각 count, setCount로 되어있는것을 볼 수 있지?
버튼 누르면 setCount()함수 호출해서 카운트 1증가시킴 그리고 count값 변경되면 컴포넌트 재렌더링되면서 새로운 카운트값 표시됨.
또 많이 쓰이는 훅은 useEffect()!
이 이팩트라는것은 서버에서 데이터를 받아오거나 수동으로 DOM을 변경하는 등의 작업을 말함 왜 이걸 이팩트라고 불러? 이 작업들이 다른 컴포넌트에 영향을 미칠수있고, 렌더링중에는 작업이 완료될수없기때문임!
이 useEffect는 클래스 컴포넌트에서 제공하는 생명주기 함수인 componentDidMount(), componentDidUpdate(), componentWillUnmount()와 동일한 기능을 하나로 통합해서 제공함 그래서 useEffect()훅만으로 생명주기 함수와 동일한 기능 수행 가능
useEffect(이팩트 함수, 의존성 배열);
첫번째 파라미터로는 이팩트 함수가 들어가고 두번째 파라미터로는 의존성 배열이 들어갑니다.
의존성 배열이란 말 그대로 이 이펙트가 의존하고있는 배열인데 배열안에 있는 변수중에 하나라도 값이 변경되었을때
이펙트 함수가 실행됩니다.
import React, {useState, useEffect} from "react";
function Counter(props) {
const[count, setCount] = useState(0);
useEffect(() => {
//브라우저 API를 사용하여 document의 title을 업데이트
document.title = `총 ${count}번 클릭했습니다.`;
});
return (
<div>
<p>총 {count}번 클릭했습니다.</p>
<button onClick={() => setCount(count + 1)}>
클릭
</button>
</div>
);
}
아까 사용했던 useState훅에 추가로 useEffect()훅을 사용한것이다. useEffect()함수를 사용하여 생명주기 함수의 기능을 동일하게 수행하도록 만든것인데 useEffect()안에 있는 이펙트 함수에서는 브라우저에서 제공하는 API를 사용해서 document의 title을 업데이트한다. 이 title은 크롬 브라우저에 나오는 탭의 제목이담.
위에처럼 useEffect를 의존성 배열없이 사용한다면 처음 컴포넌트가 마운트 되었을때 실행되고, 이후 컴포넌트가 업데이트 될때마다 실행된다.
또한 이 이펙트 함수는 컴포넌트 안에서 선언되자나 맞지? 그래서 props와 state에도 접근가능
보면 count라는 state에 접근할수있잖아.
그렇다면 componentWillUnmount()와 동일한 기능은 useEffect로 어떻게 구현이가능할까?
import React, {useState, useEffect} from "react";
function UserStatus(props) {
const [isOnline, setIsOnline] = useState(null);
function handleStatusChange(status) {
setIsOnline(status.isOnline)
}
useEffect(() => {
ServerAPI.subscribeUserStatus(props.user.id, handleStatusChange);
return () => {
ServerAPI.unsubscribeUserStatus(props.user.id, handleStatusChange);
};
});
if(isOnline === null) {
return '대기중...';
}
return isOnline ? '온라인' : '오프라인';
}
음 이 useEffect라는게 나도 아직 이해가 잘 안되는부분이라 다시정리할거임 그렇게 알아 ㅎㅎ
이걸 사용함으로써 생명주기 메소드를 함수형 컴포넌트에서도 사용할수있다는거잖아
useEffect()!!!!!!!!!!!!!!!!!!!!!!!
리액트 컴포넌트가 렌더링 될때마다 특정 작업(사이드 이펙트)을 실행할 수 있도록 하는 리액트 훅!!!!
여기서 사이트 이펙트란 컴포넌트가 렌더링 된 이후에 비동기로 처리되어야하는 부수적인 효과들을 뜻함.
자자 기본형태부터 아까 한거부터 다시보자
useEffect(function, deps)
자 여기서 function은 실행하고자하는 함수일거고,
deps는 배열형태이자 function을 실행시킬 조건이야
deps에 특정값을 넣으면 컴포넌트가 mount될때 지정한 값이 업데이트가 될때! -> useEffect를 실행하는거야
자 그러면 이때 deps부분을 생략한다면 어떻게될까? -> 그럼 해당 컴포넌트가 렌더링 될때마다 useEffect가 실행되게돼.
useEffect(() => {
console.log("렌더링 될때마다 실행");
});
만약에 맨 처음 렌더링될때 한번만 실행하고 싶으면 deps위치에 빈 배열을 넣어주면돼!!
useEffect(() => {
console.log("맨 처음 렌더링 될때 한번만 실행")
},[]);
만약에 특정 값이 업데이트 될때만 실행하고 싶을땐 deps위치의 배열안에 실행 조건을 넣어주면됨!
useEffect(() => {
console.log(name);
console.log("name값이 업데이트 될때만 실행");
},[name]);
근데 이렇게하면 업데이트될때뿐만 아니라 마운트 될때도 실행되므로 만약에 업데이트될때만 실행시키고싶으면 아래처럼 하면돼!
const mounted = useRef(false);
useEeefct(() => {
if(!mounted.current) {
mounted.current = true;
} else {
console.log(name);
console.log("업데이트 될때마다 실행");
}
},[name]);
자 그러면 어떤 예시로 쓰이는지 한번 봐보자고!
import React, {useEffect, useState} from "react";
function UseEffect() {
const [name,setName] = useState("초기 닉네임");
useEffect(() => {
console.log("컴포넌트 나타남");
console.log(name);
return () => {
console.log("clean up함수");
};
});
const onClick = () => {
setName("닉네임 변경");
};
return (
<div>
{name} <button onClick={onClick}>변경</button>
</div>
);
}
export default UseEffect;
useMemo는 Memoized value를 리턴하는 훅임.
파라미터로 create함수와 의존성 배열을 받는다.
의존성 배열에 들어있는 변수가 변했을 경우에만 새로 create함수를 호출하여 결괏값을 반환하며, 그렇지 않은 경우에는 기존 함수의 결괏값을 그대로 반환함.
이걸 사용하면 컴포넌트가 다시 렌더링 될때마다 연산량이 높은 작업을 반복하는 것을 피할수있음.
-> 결과적으로 빠른 렌더링 속도를 얻을 수 있음.
const memoizedValue = useMemo(
() => {
//연산량이 높은 작업을 수행하여 결과를 반환
return computeExpensiveValue(의존성 변수1, 의존성 변수2);
},
[의존성 변수1, 의존성 변수2]
);
useCallback() 훅은 useMemo와 유사한 역할을 함
근데 이 두가지의 차이점은 값이 아닌 함수를 반환한다는점.
마찬가지로 함수와 의존성 배열을 파라미터로 받음!
useCallback()훅에서는 파라미터로 받는 함수를 콜백이라고 부름.
그리고 의존성 배열에있는 변수 중 하나라도 변경되면 메모이제이션된 콜백함수를 반환함.
const memoziedCallback = useCallback(
() => {
doSomething(의존성 변수1, 의존성 변수2);
},
[의존성 변수1, 의존성 변수2]
);
만약 이 훅을 사용하지않고 컴포넌트 내에 함수를 정의한다면 매번 렌더링이 일어날때마다 함수가 새로 정의됨.
따라서 useCallback()을 사용하여 특정 변수의 값이 변한 경우에만 함수를 다시 정의하도록하여 불필요한 반복작업을 없애주는것임.
useRef()훅은 래퍼런스를 사용하기 위한 훅
여기서 래퍼런스란? 특정 컴포넌트에 접근 할 수 있는 객체를 말함!
'REACT' 카테고리의 다른 글
Composition (0) | 2023.07.14 |
---|---|
key & form (0) | 2023.07.14 |
Shared state (0) | 2023.07.13 |
React Foundation (0) | 2023.06.27 |
REACT (0) | 2023.04.29 |