코드캠프 FE 2일차 - TIL(React-Component,React-Hooks,State)

space's pace·2022년 5월 10일
0
post-thumbnail

📔 학습목표

  1. React 컴포넌트 >> Class형 / 함수형
  2. 함수형 컴포넌트에서도 클래스형과 동일한 기능을? >> React-Hook
  3. 컴포넌트에서 사용하는 변수 >> State

왜 리액트를 사용해야 하는가?

  1. 프론트엔드 개발자가 사용하는 라이브러리 중에서도 가장 대표적이다.
    즉, 많은 개발자가 사용한다는 것은 커뮤니티 형성이 활발하고, 리액트로 만들어진 서비스 함유율이 높다는 뜻이다.

[참조사진 - npm trend]

위와 같이 anguler,vue에 비해 react의 다운로드 횟수가 월등하게 높다.

  1. react 하나를 잘 배워두면 웹, 안드로이드, 데스크탑을 모두 만들 수 있다.

_________________________________________________________

컴포넌트(Component)

: UI 또는 기능을 부품화해서 재사용 가능하게 하는 것

기존의 html의 코드를 예를 들면,
같은 형태의 디자인의 코드를 반복 복사/붙여넣기를 하여 구성을 했다.

색상 하나를 변경하려면 일일히 수정해줘야 하는 번거로움이 있다.
하지만, 컴포넌트는 원본 하나를 만들어서 뿌려주는 개념으로 원본만 변경하면
모두 적용이 된다. 즉, 엄청 편리함!!

데이터는 각 컴포넌트에 맞게 변경하여 사용가능하다.

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

리액트 컴포넌트는 클래스형 컴포넌트 또는 함수형 컴포넌트로 작성될 수 있다.
class형 컴포넌트는 상태 값을 가질 수 있고, 리액트 컴포넌트의 생명주기 함수를 작성할 수 있다. 그러나, 함수형 컴포넌트는 이 모든 일을 할 수 없다. 즉, 이 둘의 차이점은 상태값과 생명주기의 유무에 있다.

리액트 버전 16.8부터는 훅(hook) 이 등장하면서 함수형 컴포넌트에서도 상태값생명주기 함수 코드를 작성할 수 있게 되었다. 현재는 공식문서에서도 함수형 컴포넌트을 함께 사용할 것을 권장하고 있다.


🤔 왜 함수형 컴포넌트를 권장하는 걸까?

클래스형 컴포넌트는 로직과 상태를 컴포넌트 내에서 구현하기 때문에 상대적으로 복잡한 UI 로직을 갖고 있는 반면, 함수형 컴포넌트는 state를 사용하지 않고 단순하게 데이터를 받아서(props)UI에 뿌려준다. 을 필요한 곳에 사용하며 로직의 재사용이 가능하다는 장점이 있어 함수형 컴포넌트 + 훅을 주로 사용한다고 한다.


1. Class형 컴포넌트

import React, { Component } from 'react';

class Hello extends Component {
  render() {
    const { color, name, isSpecial } = this.props;
    return (
      <div style={{ color }}>
        {isSpecial && <b>*</b>}
        안녕하세요 {name}
      </div>
    );
  }
}

export default Hello;

📌 특징
1. class 키워드로 시작함
2. 컴포넌트로 상속받음
3. render() 메소드 사용해서 JSX를 반환
4. Props를 조회할 때 this 키워드 사용

2. 함수형 컴포넌트

import React from 'react';

function Hello({ color, name, isSpecial }) {
  return (
    <div style={{ color }}>
      {isSpecial && <b>*</b>}
      안녕하세요 {name}
    </div>
  );
}

export default Hello;

📌 특징
1. JSX를 return으로 반환
2. state를 사용할 수 없다.
3. 생명주기 함수를 작성할 수 없다.


React-Hook

함수형 컴포넌트는 클래스형 컴포넌트보다 선언하기가 좀 더 편하고, 메모리 자원을 덜 사용한다는 장점이 있다. 과거에는 함수형 컴포넌트에서 state와 라이프사이클 API를 사용할 수 없다는 단점이 있었는데, 이러한 단점은 앞서 언급한 것처럼 리액트 훅이 도입되면서 해결되었다.

🤓 짧은 Q&A

Q. 함수형 컴포넌트와 클래스형 컴포넌트는 혼용해서 쓸 수 있는가?
A. 가능하다.

Q. 간단한 함수형만 알면 되지, 굳이 Class형까지 배워야 하는가?
A. 지금은 훅이 도입되면서 함수형을 쓰는 추세지만, 그럼에도 불구하고 기존에 클래스형으로 썼던 서비스들이 남아있기 때문에 알아두어야 한다.

Q. 클래스형에서 함수형으로 변경 가능한가?
A. 가능하다. 기존의 클래스형으로 써왔던 회사들도 최근에 함수형으로 변경하는 추세임.

State

state란 리액트 컴포넌트에서 데이터를 담기 위한 상자이다.
자바스크립트에선 데이터를 담기 위한 상자로 변수를 사용했다면 리액트 컴포넌트에선 state를 변수로 사용한다.

state: 컴포넌트에서 사용하는 변수
setState: 컴포넌트에서 사용하는 변수를 바꿔주는 기능
useState: 컴포넌트에서 사용하는 변수를 만들어주는 기능

변수 만들고, 바꾸기

자바스크립트는 let, const를 사용했다면
리액트 컴포넌트에서는 const [변수명] = use~(매개변수) 형식을 사용한다.


자바스크립트에서는 let, const를 사용하고 변수명 = "기존값/바꿀값" 을 쓰면 값이 바뀐다.

리액트 컴포넌트에서는 useState를 통해 바꿔준다.

리액트 컴포넌트에서는 let으로 값을 변경해줄 수는 없는 걸까?
예제를 통해 알아보자

// let으로 count 예제 실험해보기
function New() {
    let count = 0     // let으로 자바스크립트 변수 만들기
    
    function handleClick() {
        count = count + 1     // 갯수는 증가했지만, 화면에는 반영이 안됨
    }

    return (
        <div>
            <h1>{count}</h1>
            <button onClick={handleClick}>
      				let을 사용하여 count 증가
       	 	</button>
        </div>
    )
}

export default New

let으로 선언하면 카운트의 숫자는 증가했지만, 화면상으로는 반영되지 않는 문제점이 있다.

하지만, useState를 통해 위의 문제를 해결할 수 있다.

import { useState } from 'react'

export default function CounterStatePage() {

  const [count, setCount] = useState(0)

  function counter() {
    setCount(count + 1)
  }

  return (
    <div>
      {/* 그냥 카운트 쓰면 string으로 인식 */}
      <div>{count}</div>
      <button onClick={counter}>카운트 올리기!!</button>
    </div>
  )
}


💬서버로 전송하기 위해 state에 담아두기

로그인이나 회원가입 등 우리가 input태그에 입력한 값을 서버로 전송하기 위해 값을 담아두는 용도로 쓰인다.

import { useState } from 'react'

export default function SignupStatePage(){
    const [email, setEmail] = useState("")
    const [password, setPassword] = useState("")

    const [emailError, setEmailError] = useState("")

    function onChangeEmail(event){
      // event.target => 태그 전체를 의미, 예) <input type="text" />
      // event.target.value => 태그에 입력된 값
      setEmail(event.target.value)
    }

    function onChangePassword(event){
      setPassword(event.target.value)
    }

    function onClickSignup(){
      // 진짜 포장이 잘 됐는지 확인해보기
      console.log(email)
      console.log(password)

      if(email.includes("@") === false) {
        // alert('이메일이 올바르지 않습니다! @가 없음!')
        setEmailError('이메일이 올바르지 않습니다!! @가 없음')
      } else {
        alert('회원가입을 축하합니다!!') 
      }
    }

    return (
        <div>
            이메일: <input type="text" onChange={onChangeEmail} /><br />
            <div>{emailError}</div>
            비밀번호: <input type="password" onChange={onChangePassword} /><br />
            <button onClick={onClickSignup}>회원가입</button>
        </div>
    )

}

결과 화면


💬 작성한 내용을 검증하고 잘못된 부분 에러 표기하기

아이디와 비밀번호에 정해진 규칙대로 넣지 않을 시(이메일 형식인데 @를 뺀다던지) 오류를 표기하기 위해 state를 사용한다.

import { useState } from "react"

function Login () {
  
  	// set~ 바뀐 내용을 넣을 곳
    const [id, setId] = useState('')
    const [pw, setPw] = useState('')
    
    // 오류 찾기
	const [errorId, setErrorId] = useState('')
    const [errorPw, setErrorPw] = useState('')

    function handleChangeId(event) {
        const value = event.target.value
        setId(value)
    }

    function handleChangePw(event) {
        const value = event.target.value
        setPw(value)
    }

		function handleClickLogin() {
          // 아이디 칸이 공백이라면
        if(id === "") {
            setErrorId('! 아이디를 정확히 입력해 주세요.')
        }
           // 비밀번호 칸이 공백이라면
        if(pw === "") {
            setErrorPw('! 비밀번호를 정확히 입력해 주세요.')
        }
          // 아이디와 비밀번호가 공백이 아니라면(!값: 부정)
        if(id !== "" && pw !== ""){
            alert('아이디와 비밀번호가 모두 입력되었습니다. 로그인을 시작합니다.')
        }
    }

    return (
        <div>
            <h1>로그인</h1>
            <div>아이디 {id}</div>
            <input type="text" onChange={handleChangeId}/>
			<div style={{color: 'red'}}>{errorId}</div>
            <div>비밀번호 {pw}</div>
            <input type="text" onChange={handleChangePw}/>
			<div style={{color: 'red'}}>{errorPw}</div>
			<div>
                <button onClick={handleClickLogin}>
                  로그인					
              	</button>
            </div>
        </div>
    )
}

export default Login
profile
블로그 이사 준비중!

0개의 댓글