[React - Study] state , setState , useState

JooSehyun·2023년 2월 7일
0

[Study]

목록 보기
1/31
post-thumbnail

[React - Study]

state, setState, useState 란?

state

state란 무엇일까? 간단하게 생각하면 state는 변수이다. (그럼 const , let , var 가 있는데 뭐때문에 state라는 변수를 사용하지?) 라는 궁금증이 생긴다. state는 일반 변수와 다르게 값이 변하게 되면 렌더링이 일어난다. 즉, 값이 변하게 되면 연관있는 컴포넌트들이 다시 렌더링이 되어 화면이 바뀌게 된다. state와 함께 사용되는 함수는 setState이다. setStatestate의 값을 변경시켜주는 함수이다.

const [state, setState] = useState(초기값)

state는 위와 같이 선언한다. state는 변수, setStatestate를 변경시켜주는 함수 useStatestate , setStatereturn하면서 초기값을 설정해주는 hook이다.

state 값 변경하는 방법

위에서 설명했듯이 state 값은 setState 함수를 이용하여야 한다. setState 함수를 이용하여 값을 변경해야지만 reactstate값이 변경되었다는 것을 인식하여 화면을 렌더링 하기 때문이다.

state 변경 시 값 주의점

예를 들어 setState(3)을 하게 된다면 state값은 3으로 변경되면서 렌더링이 되겠지만 state=3이라고 하면 값은 변경되겠지만 렌더링이 되지 않는다. 이점을 주의하여 state값을 사용하여야 한다.

setState 시 이전 state값 사용 방법

state는 number , string , boolean 등 1개의 자료형을 넣을 수 있지만, 배열이나 객체도 사용가능

const [fruit, setFruit] = useState({color: "res", name:"apple"})

 위 state는 과일 state이다. 여기서 name만 딸기로 변경하고 싶은 경우 여러가지 방법이 있다.
1. 새로운 객체를 만들어서 setFruit하는 방법
2. fruit state를 이용하여 name만 변경하는 방법
3. prevState를 이용하여 이전 state값을 사용하여 setState하는 방법이 있다.

  1. 새로운 객체를 만들어서 setFruit 하는 방법
setFruit({color:'red',name:'strawberry'})
  1. fruit state를 이용하여 name만 변경하는 방법
setFruit({...fruit, name:'strawberry'})
  1. prevState를 이용하여 이전 state값을 사용하여 setState하는 방법
setFruit(prev => ({...prev, name:'strawberry'})

정리

  • state는 렌더링이 되는 변수
  • setState는 state의 값을 변경할때 사용하는 함수
  • useState는 state의 초기값을 정할 수 있고, return값으로 state , setState를 돌려주는 hook
  • setState함수 사용시 이전 state값을 사용하고 싶으면 prevState를 사용한다.

[출처] https://codiving.kr/21


study

import './App.css';
import React,{useState} from 'react';

function App() {
  let [글제목,글제목변경] = useState(['남자코트 추천','강남 우동 맛집','파이썬독학']);
  return(
    <div className="App">
    
    </div>
    )
  
export default App;

 함수형 컴포넌트를 생성하고 변수를 지정하여 useState 초기값을 설정한다.
state값인 글제목과 setState값인 글제목변경을 useState에 초기 배열값 '남자코트 추천','강남 우동 맛집','파이썬독학' 을 입력한다.
map함수를 만들어 배열 반복문을 만든다.

글제목.map(function(a,i){
	return(
    <div className="list" key={i}
    	<h4>{글제목}</h4>
        <p>217일 발행</p>
    </div>
    )

이렇게 까지만 적어주면 배열의 0 , 1 , 2 모두 h4에 담겨
남자코트 추천강남 우동 맛집파이썬독학 라는 글제목으로 생성된다. function의 매개변수인 순번 i를 활용하여

<h4>{글제목[i]}</h4>

로 변경해준다. 그럼 3개의 게시물에 0 , 1 , 2 번의 각 배열에 맞는 제목이 각 글제목으로 적용된다.

글제목 옆에 👍🏻을 만들어 좋아요 버튼을 만들고자 한다. h4 옆에 span 태그를 만들어 넣어준다
변수로 state값을 만든다 let [따봉, 따봉변경] = useState(0);

<h4>{글제목[i]}<span onClick={()=>{따봉변경(따봉+1)}>👍</span>{따봉}</h4>
글제목.map(function(a,i){
	return(
    <div className="list" key={i}
    	<h4>{글제목[i]}<span onClick={()=>{따봉변경(따봉+1)}>👍</span>{따봉}</h4>
        <p>217일 발행</p>
    </div>
    )

하지만 이렇게 작성을 하게 되면 게시물 전부 같은 좋아요 숫자가 올라가게 된다.

[해결]

우선 총 3개의 배열이 있으므로 useState안에 배열로 3개의 값인 let [따봉, 따봉변경] = useState([0,0,0]); 로 수정하고
state값은 원본을 건들이는 것 보단 변수로 새로 복사하여 만들어본다.

<span onClick={()=>{
		let copy=[...따봉]
		copy[i] += 1;
		따봉변경(copy)
	}}>👍🏻</span>{따봉[i]}</h4>

각자 따로 좋아요의 수가 올라간 것을 볼 수 있다.


각 제목을 클릭하면 밑에서 새로운 모달 창이 열리게 만들어야 하는데

let [modal,setModal] = useState(false)

로 state를 만들고 useState의 초기값은 false로 한다. 뭐든 on/off되는 기능은 false로 지정해놓고 만드는것이 좋다.
열리면 true 닫히면 false

function Modal(props){

  return(
    <div className="modal">
        <h4>{props.글제목[0]}</h4>
        <p>날짜</p>
        <p>상세내용</p>
      	<button>글수정</button>
    </div>
  )
}

Modal 을 만들고 return문 안에 props로 받아올 글제목과 버튼들을 만든다. 이 Modal은 부모 컴포넌트인 App 컴포넌트에 맵함수 밑에 삼항연산자로 만들고 <Modal> 컴포넌트를 참(true)일때 넣어준다. (조건문을 써야 Modal창이 켰다 꺼졌다 하기 때문이다.)

{modal === true ? <Modal 글제목={글제목}/> : null}

[해결]

우리는 Modal 컴포넌트의 button 글수정 버튼을 누르면 첫번째 글제목인 '남자 코트 추천' 이 '여자 코트 추천' 으로 바뀌길 원한다.

먼저 부모컴포넌트에 넣은 삼항연산자에 <Modal 글제목변경={글제목변경} 글제목={글제목}>글제목 변경 setState를 추가한다.

<button onClick={()=>{props.글제목변경(['여자코트 추천','강남 우동 맛집','파이썬독학'])}}>글수정</button>

부모컴포넌트에서 받아온 props를 쓰고 + setState인 글제목변경에서 0번째 '남자코트 추천'을 '여자코트 추천'으로 바꾸면 Modal창에서 글수정 버튼을 누르면 남자코트에서 여자코트로 바뀌게 된다.


그다음 우리는 Modal 컴포넌트에 <h4>{props.글제목[0]}</h4>로 되어 있는 부분이 다른 글을 클릭해도 똑같이 글제목[0] 에 해당되는 제목만 나오고 있다. 여기서 각 글제목에 맞는 창이 나와야한다

[해결]

실패

function Modal(props){
  let moTit = props.글제목;
  moTit.map(function(a,i){
  return(
        <div className="modal" >
            <h4>{props.moTit[i]}</h4>
            <p>날짜</p>
            <p>상세내용</p>
            <button onClick={()=>{props.글제목변경(['여자코트 추천','강남 우동 맛집','파이썬독학'])}}>글수정</button>
        </div>
      )
  })
}

나는 Modal 컴포넌트 안에 글제목을 props로 받아와서 다시 맵함수를 쓰는 방법이 될거 같아서 해봤다.
받아온 props.글제목 을 변수에 담아서 moTit 맵함수를 돌렸지만 실패..

해답

let [title] = useState(0);

부모 컴포넌트에 title이라는 state를 만든다.
그리고 Modal 컴포넌트에

<h4>{props.글제목[props.title]}</h4>

를 만들어주면 위에 만든 useState의 초기값인 0의 배열 제목이 생긴다.
우리는 여기서 setTitle을 사용하여 변하는 값을 만들어 줘야한다.

let [title, setTitle] = useState(0);

이렇게..

그럼 쉽게 버튼을 3개를 만들어서 비교해보면

<button onClick={()=>{setTitle(0)}}>글제목 0</button>
<button onClick={()=>{setTitle(1)}}>글제목 1</button>
<button onClick={()=>{setTitle(2)}}>글제목 2</button>

setTitle의 값이 0 , 1 , 2 로 바뀌어야한다. 부모 컴포넌트에 있는 h4에

<h4 onClick={()=>{setTitle(i)}}></h4>

setTitle(i)로 넣게 되면 map함수 반복문이 i번째가 계속 0 , 1 , 2 로 바뀌므로 넣어주면 끝이다.

그리고 자식 컴포넌트가 props를 물려받아야 하니 삼항연산자에 추가된 Modal 컴포넌트에

<Modal title={title}>

추가해준다.

👀 Modal에 직접 그럼 title의 state를 만들면 되는거 아닌가 라고 궁금할 수 있다.
물론 props로 전송할 필요 없이 편하게 사용하겠지만 state가 Modal, App에서 필요하면 App에 만들어놔야한다
state를 만드는 곳은 state를 사용하는 컴포넌트들 중 최상위 컴포넌트에 보관하는게 좋다.


[해결]

계속 만지다 보니 이상한 점이 발견되었다.

span 태그를 클릭하는데 h4에 onClick 하여 실행되는 Modal창이 열린다. 이는 span태그가 클릭이 되면 h4의 이벤트도 활성화가 되기때문이다. 이런 경우를 이벤트 버블링이라고 하는데

<span onClick={(e)=>{e.stopPropagation();}

파라미터로 e를 넣어준다. 이벤트객체인데 e.stopPropagation();를 적어주면 더이상의 이벤트 버블링이 없이 span 따봉만 눌리면서 Modal창은 가만히 있게된다.


Input의 종류와 타입들이 있다.

  • range : 막대그래프바
  • checkbox : 체크박스
  • text : text 인풋
  • date : 날짜 입력
  • select : 셀렉트 박스
  • textarea : 텍스트를 입력하는 공간
<input type="range"></input>
<input type="checkbox"></input>
<input type="text"></input>
<input type="date"></input>
<select></select>
<textarea></textarea>

이벤트 핸들러

  • onMouseOver
  • onScroll
  • onChange

예제

<input onChange={(e)=>{입력값변경(e.target.value); console.log(입력값);}}></input>

이렇게 onChange 안에 e:이벤트객체 변수 e.target.value를 넣게 되면 콘솔창에 직접 입력하는 모든 값이 나오게 된다.

그러면 input에 입력한 value가 콘솔로그에 나타나게 되는데 이상한 점이 있다. 왜냐하면 'f'를 한번 치면 콘솔로그 value값이 나오지 않고

' f ' 를 한번 입력되면 아래와 같이 콘솔창에 아무것도 뜨지 않는다.

두번째 부터 콘솔로그에 value값이 나타난다.

' f ' 를 두번 입력하면 콘솔창에 나타나게 된다.

🕵️ [Tip] : state 변경함수는 늦게처리되고 용어로는 비동기처리 라고 한다. 바로 다음에 있는 console.log(입력값); 를 실행하려고 하는 특성이 있기 때문이다. state가 변경되기전에 다음번이 먼저 실행됨


0개의 댓글