React 컴포넌트 안의 State와 생명주기에 대한 개념
: 컴포넌트의 생명주기는 컴포넌트가 브라우저에 나타나고 업데이트 되고, 사라지게 될 때 호출되는 메서드.
→ 특정 시점에 코드가 실행되도록 설정할 수 있다는 것!
render
인풋창 그리기componentDidMount
포커스 깜빡 깜빡 하기componentDidUpdate
componentWillUnmount
어떻게 구현할까?
일단 인풋이 그려져야 한다. → 그리고 난 뒤 깜빡깜빡 명령을 등록!
**// class 컴포넌트의 생명주기**
import {Component} from 'react'
import Router from 'react'
export default class ClassCounterPage extends Component{
state = {
count : 0,
}
**//라이프사이클 메서드**
componentDidMout(){
console.log("마운트 됨")
//input태그 선택해서 **포커스 깜빡**거리게 하기
}
componentDidUpdate(){
console.log("수정하고 다시 그림!!")
}
**// 리랜더링 되고 실행되는 함수**
componentWillUnmount(){
console.log("여기서 나갈래요")
**//나가기 전에 마지막으로 할 것들
// 채팅방나가기!
// Api 요청
// 언제 쓸까? 채팅방에 접속했다고 가정했을때, 접속한 채팅방에서 나가기 버튼을 클릭하게 된다면
// 인원수가 6 -> 5 로 변할때 다른 사람들도 인원수가 변하는 걸 알아야 한다.
// 나간다 -> 백엔드에 요청 -> 백엔드가 채팅방에 접속한 다른 브라우저들에게 5라는 값을 다시 보내준다.**
}
**// 카운트 올리기 함수**
onClickCouter = ()=>{
console.log(this.state.conut)
this.setState(((prev))=>({
count : this.state.count(=prev.count) +1
}))
}
// 현재 페이지 나가기 함수 _ componentWillUnmount를 보기위한
onClickMove = () => {
router.push('/')
}
**// 화면 그리는 부분**
render(){
return(
<div>
// this는 class 자기자신을 뜻합니다.
<div>현재 카운트 : {this.state.count}</div>
// 직접 바인딩 하실때는 onClick={this.onClickCouter.bind(this)} 라고 적어주셔야 합니다.
<button onClick={this.onClickCouter}>카운트 올리기</button>
<button onClick={this.onClickMove}>나가기</button>
</div>
)
}
}
// 의존성 배열[]에 아무것도 넣지 않으면 Mount시에만 렌더해주고 끝나게 됩니다.(1번만 실행)
// 처음에만 실행되고 다시는 실행되지 않음!
useEffect(()=>{
console.log("마운트 됨!!")
},[])
// 의존성 배열이 없기 때문에 뭐 하나라도 바뀌면 **무조건 다시 실행**됩니다.
// **의존성 배열[] 이 없음! -> componentDidUpdate와 똑같지는 않음
// 처음에도 한번은 실행이 되기 때문.**
useEffect(()=>{
console.log("수정하고 다시 그려짐!!")
})
// someState가 수정될때만 리렌더 해주기
useEffect(()=>{
console.log("수정하고 다시 그려짐!!")
},[someState])
useEffect(()=>{
console.log("수정하고 다시 그려짐!!")
//이부분이 끝나고 진행할 것들
return(()=>{
console.log("여기서 나갈래요!!")
})
})
componentDidUpdate와 비슷하지만 다른점 하나는, Mount 되자마자 실행되는 점.
두개를 하나로 합칠 수도 있다.
return 문을 아래로 추가시켜 준다면!
(마운트, 언마운트)
💡 useEffect의 실행 시점
→생명주기 메서드,훅 은 기본적으로 렌더(화면그리기) 이후에 실행됩니다.
따라서 useEffect와 lifecycle 메서드는 렌더 이후에 실행됩니다.
💡 useEffect 안에서 setState의 사용🔥
→useEffecrt 내에서 setState를 사용할때는 정말 필요한 경우가 아니라면 지양하시는게 가장 좋습니다.
컴포넌트가 마운트된 이후에 setState를 적용하게 되면,
1. state가 변경되고,
2. 변경된 state로 컴포넌트가 다시그려지게(=리렌더) 됩니다.
즉, useEffecrt 내에서 setState를 사용하게 되면 불필요한 리렌더나 무한루프를 일으키게 되고 성능면에서 비효율적이게 됩니다.
// useEffect 의 잘못된 사용 예제 (1. 추가랜더링, 2. [count] 까지 잘못 설정했을시 -> 무한루프;)
// useEffect 안에서 setState는 무한루프를 불러일으킬 수 있고 비효율적임.
useEffect(() => {
setCount(10);
}, [count]);
주의 : 일단 랜더가 다 된 이후에 실행되는 것들임 useEffect
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
export default function CounterPage() {
const [count, setCount] = useState(99);
const router = useRouter();
// 생명주기 하나로 통합
useEffect(() => {
console.log("마운트됨!!!");
// 포커스 깜빡깜빡
}, []);
useEffect(() => {
console.log("수정되고 다시그려짐!!!");
});
//
useEffect(() => {
return () => {
console.log("컴포넌트 사라짐!!!");
};
// 채팅방 나가기
// api 요청!!!
}, []);
const onClickCounter = () => {
setCount((prev) => prev + 1);
};
const onClickMove = () => {
router.push("/");
};
return (
<div>
<div>현재카운트: {count}</div>
<button onClick={onClickCounter}>카운트 올리기!!!</button>
<button onClick={onClickMove}>나가기!!!</button>
</div>
);
}
state.comment = "hello"
이 코드는 다시 렌더링 하지 않음
대신에 setState() 를 사용한다.
setState({comment: "hello"})
React는 성능을 위해 여러 setState() 호출을 단일 업데이트로 한꺼번에 처리할 수 있다.
props, state가 비동기적으로 업데이트 될 수 있기 때문에 다음 State를 계산할 때 해당 값에 의존 X
this.setState({
counter: this.state.counter + this.props.increment,
});
다음 코드는 카운터 업데이트에 실패할 수 있다.
객체보다는 함수를 인자로 사용하는 다른 형태의 setState()를 사용한다.
그 함수는 이전 State를 첫 번째 인자로 받아들이고, 업데이트가 적용된 시점의 props를 두 번째 인자로 받아들인다.
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
화살표 함수를 사용했지만, 일반적인 함수에서도 정상적으로 작동
setState를 호출할 때 React는 제공한 객체를 현재 state로 병합
ex) state는 다양한 독립적인 변수를 포함할 수 있다.
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}
별도의 setState 호출로 이러한 변수를 독립적으로 업데이트 가능
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
병합은 얕게 이루어진다. setState({comments}) 는 state.posts에 영향을 주진 않지만 state.comments는 완전 대체 됨.