REACT_기본문법 4. State

Eunsu·2021년 10월 22일
0

@ React

목록 보기
10/11
post-thumbnail

네 그래요 props를 알아봤습니다. 잘봤구요
state에 대해서 알아볼께요! state공부하고 집에갈꺼에요 총총총
체력이 남으면 lifecycle까지 볼건데 아마 그때는 체력이 바닥나지 않을까 ^^;;;

State란?

state는 어떤 컴포넌트에만 한정하여 사용되는 데이터를 포함하며, 해당 데이터는 시간이 지남에 따라 변경될 수 있다. state는 사용자가 자유롭게 정의할 수 있으며, 일반적인 자바스크립트 객체이어야 한다.
(데이터타입인 string,boolean,number,object,array,null이 들어갈 수 있다.)

어떤 값이 렌더링 또는 데이터 흐름 상에서 (예를 들어, 타이머의 ID) 사용되지 않는다면, 해당 값을 state에 넣지 않아도 된다. 그러한 값은 컴포넌트 인스턴스의 필드로 정의할 수 있다.

Props는 불변하지만, State는 이변한 값으로 정의 할 수 있다.

setState()

setState()는 컴포넌트 state의 변경사항을 대기열에 집어놓고, React에게 해당 컴포넌트와 그 자식들이 갱신된 state를 사용하여 다시 렌더링되어야 한다고 알린다. 이 메서드는 이벤트핸들러와 서버응답 등에 따라 UI를 갱신할 떄에 가장 많이 사용하는 메서드이다.

setState()는 즉각적인 명령이 아니라 요청이다. React는 이 매서드의 실행을 지연시킬수도, 여러 컴포넌트를 한번에 갱신할 수도 있다. tate 변화가 즉시 적용되는 것을 보장하지 않는다.

setState()는 state를 항상 즉각적으로 갱신하지 않는다. 그래서 setState()를 호출하자마자 state에 접근하는것이 문제가 될 수 있다. 그 대신 useEffect나 setState의 콜백함수를 사용하는 것이 좋다.

useEffect()가 false를 반환하지 않는다면(로드가 오류가 나지 않는다면) setState()는 항상 렌더링이 다시 발생하도록 만든다.새로운 state가 이전의 state와 다를 때에만 setState()를 호출해야, 불필요하게 다시 렌더링이 발생하지 않습니다.

setState(updater, [callback])
  • updater 함수

updater(state, props) => stateChange

state는 변경 사항이 적용되는 시점에 컴포넌트가 가지는 state에 대한 참조.state와 props를 기반으로 새로운 객체를 만들어서 변경 사항을 표현해야 한다.

  • callback 함수

setState의 실행이 완료되고 컴포넌트가 다시 렌더링된 뒤에 실행될 함수에 대한 콜백으로, 생략가능하다. 보통 이러한 방식의 실행에는 useEffect()의 사용을 권장한다.

클래스형 컴포넌트 state VS 함수형 컴포넌트 state

1초씩 리렌더링되는 초시계만들기

// ClockClass.jsx

class ClockClass extends React.Component{
  constructor(props){
    super(props);
    this.state={
      date:new Date()
    }
  }
  componentDidMount(){
    this.timer= setInterval(() => {
      this.tick()
    },1000)
  }
  componentWillUnmount(){
    clearInterval(this.tick)
  }
  tick(){
    this.setState({
      date:new Date()
    })
  }
  render(){
    return(
      <>
      {this.state.date.toLocaleTimeString()}
      </>
    )
  }
}

export default ClockClass;

매서드 호출 순서

  1. <App />이 호출되면 컴포넌트를 찾아 <ClockClass.jsx /> 컴포넌트로 들어감. Clock은 constuctor를 호출하고, 현재 시간이 포함된 채로 state를 초기화함.
  2. render함수를 실행하면, 리액트를 랜더링 출력값(시간)을 일치시키기 위해 DOM을 업데이트 함.(html div text바뀜)
  3. ClockClass출력값이 DOM에 삽입되면, componentDidMount() 생명주기 매서드를 호출. 매초 tick()을 호출하기 위한 타이머를 설정하도록 브라우저에 요청.
  4. 매초 브라우저가 tick()함수 호출. tick함수는 state 변경내용을 담고있음. state가 바뀌므로 render 함수 호출. => 이때 render안의 this.state.date가 달라지고 렌더링 출력값은 업데이트 된 시간을 포함해, DOM을 업데이트함.
  5. Clock 컴포넌트가 DOM으로부터 한 번이라도 삭제된 적이 있다면 React는 타이머를 멈추기 위해 componentWillUnmount() 생명주기 메서드를 호출.

//clockFunction.jsx
import { useEffect, useState } from "react";

const ClockFunction = () => {
  const [date, setDate] = useState(new Date());
  const timer = setInterval(() => {
    setDate(new Date());
  },1000)
  useEffect(() => {
    timer
  },[date]);
  return <div>{date.toLocaleTimeString()}</div>;
};

export default ClockFunction;

생명주기와 useEffect에 대해서는 다음 포스팅 주제로 할꼬임~~~!

✔setState 올바르게 사용하기

state는 직접 수정 불가. Always setState사용

const [data,setData]= useState({user:'John'});
data = {user: 'Bob'} // 수정 안됨.
setData({user:"Bob"}) //setState 사용!

State 업데이트는 비동기적일 수도 있음.

리액트는 성능을 위해 여러 setState 호출을 단일 업데이트로 처리 할 수 있다. props와 state가 비동기적으로 업데이트 될 수 있기 때문에, state를 계산할 때 해당 값에 의존하면 안된다.

State 업데이트는 병합가능함.

setState()를 호출할 때 React는 제공한 객체를 현재 state로 병합할 수 있다.

const [data,setData]= useState({
		posts:[],
  		comments:[]
	})

useEffect(()=> {
		 fetchPosts().then(response => {
			setData(...data,posts:response.posts)
    });

    fetchComments().then(response => {
 setData(...comments,posts:response.comments)
    });
}
         )

state는 완전히 대체됨.
(마지막 부분은 class 컴포넌트 관점이다. 하지만 난 class함수에 대한 이해도가 높지 않기 때문에 설명이 많이 부족함... )

state데이터는 아래로 흐름.

이 때문에 state는 종종 로컬 또는 캡슐화라고 불린다. state가 소유하고 설정한 컴포넌트 이외에는 어떠한 컴포넌트에도 접근할 수 없다.

일반적으로 이를 “하향식(top-down)” 또는 “단방향식” 데이터 흐름이라고 한다. 모든 state는 항상 특정한 컴포넌트가 소유하고 있으며 그 state로부터 파생된 UI 또는 데이터는 오직 트리구조에서 자신의 “아래”에 있는 컴포넌트에만 영향을 미친다.

트리구조가 props들의 폭포라고 상상하면 각 컴포넌트의 state는 임의의 점에서 만나지만 동시에 아래로 흐르는 부가적인 수원(water source)이라고 할 수 있다.

출처 / 참조 : https://ko.reactjs.org/docs/state-and-lifecycle.html [React 공식 홈페이지]

profile
function = (Develope) => 'Hello World'

0개의 댓글