[TIL-38] React-State

da.circle·2022년 10월 19일
0

TIL

목록 보기
38/44

Class형 컴포넌트 vs 함수형 컴포넌트

Class형

  • state, 생명주기 때문에 사용
  • 클래스로부터 한번 인스턴스가 생성이 되면 독립적으로 움직일 수 있다.

함수형

  • 한번 호출되고 메모리상에서 사라진다. → state, 라이프 사이클 사용 불가
  • 클로저를 통해 위 문제를 해결 (클로저는 추후 학습 예정)

Hook

  • 리액트는 class형 / function 형 컴포넌트가 있다.
  • 컴포넌트 안에서 상태값과 생명주기(렌더링 시작 - 끝)를 관리할 수 있다.
  • class보다 function이 메모리 등의 측면에서 효율적이지만 원래 function형은 상태값을 관리할 수 없었다.
  • function형에서 상태값을 관리할 수 있는 기능이 Hook이다.
  • 내장 Hook : useState

사용 이유

  • 컴포넌트 사이에서 상태 관련 로직을 재사용하기 어렵다.
  • 복잡한 컴포넌트는 이해하기 어렵다.
//생명주기에서
componentDidMount() {
   applyFirstLogic() //이 로직과 
   applySecondLogic() //이 로직은 전혀 상관없는 로직일 수도 있음
}

Hook 사용 조건

  1. 최상위(at the top level)에서만 Hook을 호출해야한다.
    • 반복문, 조건문, 중첩된 함수 내에서는 error
  2. React 함수 컴포넌트 내에서만 Hook을 호출해야 한다.
    • custom Hook(직접 작성한 Hook)에서도 Hook을 호출할 수 있다.

State

  • 상태
  • 컴포넌트 내부에서 가지고 있는 컴포넌트의 상태값이다.
  • 화면에 보여줄 컴포넌트의 UI정보(상태)
  • state는 컴포넌트 내에서 정의하고 사용한다.
  • 데이터는 변할 수 있는 상태값이다.

const [읽어들일 상태값, 상태값 변경 함수] = useState("상태값의 기본값");

//useState는 react의 내장 Hook이다.
import React, { useState } from 'react';

function State() {
  	//Hook 사용조건 : 최상위에서만 Hook 호출하기
	const [color, setColor] = useState('red');
	
	return (
      <div>
        <h1 style={{ color: color }}>Function Component | State</h1>
				<button onClick={() => setColor('blue')}>Click</button>
      </div>
  );
}

export default State;
cornflowerblue
  • style={{color: color}}
    • color는 글자색 color 속성명, color는 위의 state에서의 color값이다.
      기본값은 red이므로 처음에는 color : red가 적용되어 있다.
  • onClick={() => setColor('blue')}
    • button을 클릭했을 때 color의 상태값이 red에서 blue로 바뀐다.

댓글 달기 기능을 구현해보자

  • 오늘 과제 중 댓글 달기 부분이 이해가 잘 되지 않고 코드도 너무 길어서 나름 간단하게 만들어 봤다.

  1. Comment.js
import React, { Fragment, useState, useRef } from "react";
import "./Comment.scss";


function AddComment() {
  //댓글 목록을 관리하는 state
  //댓글들의 id와 content가 객체 형태로 commentArray에 들어간다.
  let [commentArray, setCommentArray] = useState([]);

  //여기서 id는 고유한 key값이다.
  const [id, setId] = useState(1);
  
  //댓글을 작성하는 input을 선택한다.
  const value = useRef();

  //댓글 다는 함수
  const addComment = () => {
    //id값에 1을 더해서 중복되지 않게 한다.
    setId(id + 1);
    
    //commentArray에 들어갈 newComment 객체
    const newComment = {
      id: id,
      //댓글input의 값을 가져온다.
      content: value.current.value,
    };
    //Spread 연산자를 사용해서 commentArray에 newComment객체를 추가한다.
    setCommentArray([...commentArray, newComment]);
  };
  return (
    <Fragment>
      <div className="flexContainer">
        <div>
          <input type="text" placeholder="댓글입력" ref={value} />
          //button을 클릭하면 addComment 함수 실행
          <button onClick={addComment}>게시</button>
        </div>
        <div className="newCommentArea">
          //commentArray배열을 순환하면서 key자리에는 id를, content자리에는 content를 넣는다.
          {commentArray.map((comment) => {
            return (
              <p key={comment.id}>
                <span className="writer">writer</span>
                <span className="content">{comment.content}</span>
              </p>
            );
          })}
        </div>
      </div>
    </Fragment>
  );
}

export default AddComment;

state에서 고유한 key값이 필요한 이유

  • Key는 React가 어떤 항목을 변경, 추가 또는 삭제할지 식별하는 것을 돕습니다.(공식문서)
  • key는 엘리먼트에 안정적인 고유성을 부여하기 위해 배열 내부의 엘리먼트에 지정해야 합니다.(공식문서)
    React공식페이지 : lists-and-keys

useRef()

  • ref : 특정 DOM을 선택할 수 있다. (getElementById, querySelector같은 느낌)
  • useRef() : 함수형 컴포넌트에서 사용하는 Hook 함수이다.
  • import { useRef } from "react";
  • 사용방법 : input을 선택할 때
const value = useRef();

//해당 input의 값 가져오기
value.current.value
~~~
//원하는 태그에서 ref = {}
<input type="text" ref={value} />

참고 ) 벨로퍼트와 함께하는 모던 리액트-useRef

Spread 연산자

  • 객체, 배열을 하나씩 분리하여 전개할 때 쓰인다.
  • const 배열명 = [spread한 배열, 추가할 값] 이렇게 작성하면 spread한 배열에 값을 추가할 수 있다.
const arr1 = [1,2,3,4,5];

console.log(arr1); // (5) [1,2,3,4,5]
console.log(...arr1); // 1 2 3 4 5

const addNumArr = [...arr1, 6]
console.log(addNumArr); //(6) [1, 2, 3, 4, 5, 6]
  • 문자열도 가능
const arr5 = [..."music"];
console.log(arr5); // ["m","u","s","i","c"]
  • 연산해보기
function get(one,two,three){
    console.log(one+two+three);
}

const arr6 = [10,20,30];
get(...arr6); //60
  • 배열 합치기(concat처럼 사용)
const arr2 = [1,2,3];
const arr3 = [4,5,6];

const arr4 = [0,...arr2,3.5,...arr3];
console.log(arr4); //(6) [0,1,2,3,3.5,4,5,6]

Array.map()

  • 배열에 있는 모든 요소들에 대해 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환한다.
    (mdn 문서의 내용이지만 이렇게 적으니까 무슨 말인지 이해가 되지 않는다😅)
//arr의 요소들을 모두 2배로 만들어서 새로운 배열을 만들어보자.
const arr = [1,2,3,4];

const doubleArr = arr.map(x => x*2);
console.log(doubleArr); //(4) [2, 4, 6, 8]

//-----------------------------------------

//객체가 들어있는 배열에서 map을 사용해보자!
const arr = [
  {key : 1,value : 10},
  {key : 2,value : 20},
  {key : 3,value : 30}
]

//arr배열을 순환한다.
const newArr = arr.map((obj) => {
   let rObj = {};
   rObj[obj.key] = obj.value;
   return rObj;
});

console.log(newArr);
/*
(3) [{…}, {…}, {…}]
0: {1: 10}
1: {2: 20}
2: {3: 30}
length: 3
*/

참고) mdn-Array/map


  1. Comment.scss
* {
  box-sizing: border-box;
}

.flexContainer {
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 50px;
}

input {
  width: 300px;
  height: 35px;
  border: 1px solid #dbdbdb {
    radius: 5px;
  }
  &:focus {
    outline: none;
  }
}

button {
  background-color: #dbdbdb;
  margin-left: 10px;
  width: 50px;
  height: 35px;
  cursor: pointer;
  border: none {
    radius: 5px;
  }
}

.writer {
  font: {
    weight: 700;
  }
  margin-right: 8px;
}

결과물..

댓글 달기 과제는 처음에 손도 대지 못했다. state가 어색하다. 시간이 나는대로 이것저것 만들어보면서 익숙해져야 할 필요를 느꼈다.

profile
프론트엔드 개발자를 꿈꾸는 사람( •̀ ω •́ )✧

0개의 댓글