본문 바로가기

WINK-(Web & App)/React.js 스터디

[2025 1학기 React.js 스터디] 이상래 #3주차

반응형

벌써 3주차... 후딱 해치워 버리겠습니다 ㅋ

  ㄴ 후딱 안되네...

 

🔍 리액트 탄생 이유

우선 지난주에 했던 최종 프로젝트만 보더라도 HTML로 구성된 UI를 제어하려면 DOM을 변형시켜서 제어를 했는데요,,

이런식으로 말이죠

하지만 웹 애플레케이션의 규모가 커지면 이런 코드들도 많아지고, 모두 DOM을 직접 건드리기 때문에 처리 할 이벤트/ 관리해야 할 상태값/ DOM 이 모두 다양해지게 됩니다. 이에 따라 업데이트를 하는 규칙도 복잡해지게 됩니다 !!

 

이런식으로 규모가 커지면 더 복잡해지겠죠???

기존 프레임 워크와의 차별점

 

  • 기존  Ember, Backbone, AngularJS 등의 프레임 워크 : JS 특정 값이 바뀌면 특정 DOM의 속성이 바뀌도록 연결 => 업데이트 하는 작업 간소화
  • React : 어떤 상태가 바뀜 => 처음부터 새로 만들어서 보여준다

- Virtual DOM 사용 : 메모리에 가상으로 존재하는 DOM ( JavaScript 객체)

- 업데이트를 어떻게 할지 고민 x + 빠른 성능 

  1. 상태가 업데이트
  2. 업데이트가 필요한 곳의 UI를 Virtual DOM 을 통해 렌더링
  3. 실제 브라우저에 보여지는 DOM과 비교후 차이 있는 곳 감지
  4. 실제 DOM에 패치

🔍  작업환경 준비

다른건 이미 다 깔려있어서 Yarn만 설치해 줬습니다

새 프로젝트 만들어서
페이지까지 띄웠슴다


🔍  컴포넌트 & JSX & 주석

컴포턴트:  리액트에서 UI를 구성하는 기본 단위 블록

 

컴포넌트의 특징
  1. 독립적이고 재사용 가능:
    • 마치 레고 블럭처럼, 조립해서 하나의 페이지를 만들 수 있음
  2. 함수형 또는 클래스형으로 만들 수 있는데, 요즘은 함수형 컴포넌트 + 훅(Hooks) 조합을 더 많이
  3. **Props(속성)**를 통해 데이터를 부모 → 자식 컴포넌트로 전달할 수 있음

이렇게 Hello라는 함수형 컴포넌트를 만들어서
import하고 <Hello />로 적용 시킬 수 있습니다

 

++추가로 Index.js 파일을 보면 이런 코드가 있는데

ReactDOM.render(<App />, document.getElementById('root'));

<div id="root"></div> // public/index.html에 있는 코드, 리액트 앱이 실제로 그려지는 공간

 

  • ReactDOM.render 의 역할은 브라우저에 있는 실제 DOM 내부에 리액트 컴포넌트를 렌더링하겠다는 것을 의미
  • 리액트 컴포넌트가 렌더링 될 때에는, 렌더링된 결과물이 위 div 내부에 렌더링되는 것 

JSX: 리액트에서 사용하는 문법 - HTML처럼 생겼지만 실제로는 JS

 

리액트 컴포넌트 파일에서 XML 형태로 코드를 작성하면 Babel 이 JSX 를 JavaScript 로 변환

 

XML : HTML과 매우 비슷한 문자 기반의 마크업 언어

Babel : 자바스크립트의 문법을 확장해주는 도구, 구형 브라우저같은 환경에서도 제대로 실행 할 수 있게 해주는 역할

 

JSX의 기본 규칙

 

  • 태그는 무조건 닫혀야 한다.

HTML에서는 <br> 같은 태그를 사용 할 때 닫지 않고 사용하기도 하지만 리액트에서는 그렇게 하면 안됨!

- Self Closing 태그 : 태그와 태그 사이에 내용이 들어가지 않을때 열리고 바로 닫히는 태그

이렇게 직접 꼭 닫아줘야 합니다..

  • 태그가 2개 이상일 땐 하나의 태그로 감싸져 있어야 한다.
function App() {
  return (
    <h1>안녕!</h1>
    <p>잘 지내?</p>
  );
}		//에러 



function App() {
  return (
    <div>
      <h1>안녕!</h1>
      <p>잘 지내?</p>
    </div>
  );
} 		// ㅇㅇ

 

이렇게 위 예제를 보면 h1 , p태그 두개라서 하나의 태그로 감싸야 합니다.

 

하지만 div로 감싸게 되면 스타일 관련 설정에 복잡해 질수도 있어서 Fragment라는 것을 사용!!

 

Fragment : 불필요한 HTML 태그 없이 감쌀 수 있게 해주는 부모 요소의 대체제 - 태그를 이름 없이 작성하면 만들어짐

 

function App() {
  return (
    <>
      <h1>안녕!</h1>
      <p>잘 지내?</p>
    </>
  );
}

 

JSX 안에 자바스크립트 값 사용하기

 

 

logo : logo.svg에서 가져온 자바스크립트 변수

-이런 변수를 JSX에서 사용하려면 {logo} 처럼 중괄호로 감싸서 사용 !

 

style & className

 

 

- 인라인 스타일은 객체 형태로 작성

- background-color 같이 -이 들어간 이름은 camelCase형태로 네이밍

- CSS class 설정 할 때 class= 이 아니라 className= 

 

주석 :  {/* 이런 형태로 */}  작성 , 열리는 태그 내부에서는 // 도 가능 

근데 //를 쓰려면 한 줄로는 안됩니다 ~~!


🔍  props를 통해 컴포넌트에게 값 전달하기

props:  properties의 줄임말 - 값을 컴포넌트에게 전달해줘야 할 때 사용

 

props의 기본 사용법

 

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <Hello name="react" /> // 기본사용
  );
}

export default App;

이런식으로 Hello 컴포넌트를 사용 할 때 name이라는 값을 주고 싶다면 코드를 작성합니다 !

 

import React from 'react';

function Hello(props) {
  return <div>안녕하세요 {props.name}</div>
}

export default Hello;

 

- Hello 컴포넌트에 전달되는 props는 객체 형태로 전달 됨

- props.name 으로 name 값 조회 가능

- 다른 언어랑 비슷 !

 

여러개의 props & 비구조화 할당

 

비구조화 할당 : 배열이나 객체 속성을 해체하여 개별 변수에 값을 담을 수 있는 JavaScript 표현식 (a.k.a 구조 분해 할당)

 

🎨비구조화 할당의 장점은?

  • 배열, 객체 내 값을 추출하는 코드가 매우 간단해진다.
  • 필요한 객체와 나머지 요소 분리가 매우 간단하다.
  • 기본값 지정이 가능하다.
let options = {
  title: "Menu",
  width: 100,
  height: 200
}
//  할당 연산자 우측엔 분해하고자 하는 객체를, 좌측엔 상응하는 객체 프로퍼티의 '패턴’을 넣는다. //
let {title, width, height} = options

alert(title)  // Menu
alert(width)  // 100
alert(height) // 200
import React from 'react';

function Hello(props) {
  return <div style={{ color: props.color }}>안녕하세요 {props.name}</div>
}

export default Hello; // App 컴포넌트에서 Hello컴포넌트로 name과 color 두개의 props를 전달했을때



//비구조화 할당 사용
import React from 'react';

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

export default Hello;

 

defaultProps 로 기본값 설정 (feat. 안쓰는게 더 편해, React 18부터 클래스형 컴포넌트에만 지원)

 

이렇게 Hello 컴포넌트에 name의 default 값을 지정해주고

 

name을 따로 지정하지 않은 Hello 컴포넌트를 렌더링 해보면?

 

왜 default로 지정한게 안뜰까요..?

 

이유를 찾아 봤는데요 바로 ES6 구조 분해 할당이 defaultProps보다 먼저 실행돼서 라고 하네요

 

function Hello({color, name}) {}
이렇게 구조 분해 할당을 함수 매개변수에서 직접 해버리면,
defaultProps가 적용되기 전에 name이 undefined로 초기화 된다고 합니다...!!

 

✅ 해결 방법

방법 1: 구조 분해를 함수 안에서 

근데 저는 이렇게 해도 안되더라고요? react 버전 떄문인가.. 그래서!

방법 2: 매개변수에서 기본값 직접 지정 - defaultProps 필요없음  

이렇게 하니까 잘 되더라고요 그리고 이게 더 간단해서 좋은거 같습니다..!

 

props.children

 

컴포넌트 태그 사이에 넣은 값 조회 하고 싶을 때 조회

Wrapper 태그로 감싸줬습니다.
props.children을 렌더링 해야 내부의 Hello 컴포넌트의 내용들이 보임 !!


🔍  조건부 렌더링

조건부 렌더링: 특정 조건에 따라 다른 결과물을 렌더링 하는 것

 

- 삼항연산자를 사용 - 주로 특정 조건에 따라 보여줘야 하는 내용이 다를 때 사용

- && 연산자 사용 - 내용이 달라지는게 아닌 단순히 특정조건에 따라 보여주고 안보여주고 해서 더 간편

 

이렇게 값 선언을 생략하고 이름만 쓰면 true로 간주합니다 !!


🔍  useState 를 통해 컴포넌트에서 바뀌는 값 관리하기

함수형 컴포넌트에서 상태 관리하기  : Hooks라는 기능

-useState도 Hokks 중 하나

 

이런 상태에서 동적인 처리를 하게 해주는 함수..!

 

 

  • 첫줄은 리액트 패키지에서 useState 함수를 불러와 주는 코드
  • Const [number, setNumber] = useState(0) 는 const [값, set값] = useState() 의 구조에서 쓴 코드
    • number : 현재 숫자 , setNumver : 상태를 변경 할 때( 버튼을 누르면 ), useState(초기값) : 초기값 설정 (number에 들어감)
  • 그 뒤로는 각 이벤트가 일어나면 setNumber 함수를 이용해서 현재숫자를 바꿔주고 이 현재 숫자를 화면에 출력합니다 !

함수형 업데이트

 

기존 값을 어떻게 업데이트 할 지에 대한 함수를 파라미터로 넣어주는 방식!

 

🔍 차이점 !!

  • 함수형 업데이트를 쓰지 않으면 "비동기적 업데이트"가 여러 번 일어날 땐 문제가 생길 수 있다!
    • 쉽게 말해 여러 번 상태를 바꾸려고 하면 기대값과 다르게 나올 수 있다.
일반 업데이트 setNumber(number + 1) 그냥 지금 보이는 값으로 계산함
함수형 업데이트 setNumber(prev => prev + 1) 최신 상태 기준으로 안전하게 계산함 ✅

 

 📚과제

자 여기 까지 배우면 과제 할 수 있을거 같아서 트라이 해봤습니다....

 

Introduce.js

  • useState 함수 사용해야 하니까 import 해주고
  • Introduce 컴포넌트에 name, age, hobbyfmf Props로 전달받도록 해줬습니다!!
  • 그리고 좋아하는 음식 몇개를 배열에 담고, useState 문법에 맞게 food에 초기값으로 (인덱스로 쓰일) 0을 넣어줬습니다
  • 그리고는 위에서 배운대로 함수형 업데이트를 사용해 줬습니다 !! - 배열에서 돌도록/배열범위를 넘어서면 다시 처음으로 돌아가도록
  • 마지막으로는 Props로 받은 정보들을 이용해 출력 해주고 누르면 음식이 바뀌는 버튼을 하나 만들어 줬습니다

App.js

  • 먼저 Introduce 컴포넌트를 임포트 해주고
  • css 스타일은 두개로 나눠서 정의 해줬는데 자기소개 카드 스타일이랑 전체화면 중앙으로 옮기는 거 정도 해줬습니다....
  • 그리고 카드 가운데로 옮기게 스타일 적용시키고
  • 렌더링 할 때는 자기소개 카드니까 위에 제목 으로 적어주고
  • 카드 스타일 적용 하고
  • 위에 Introduce 컴포넌트에 props 값 지정 해줬습니다 (기본값 지정 안해놔서 꼭 해줘야 해요)

엄.. 이렇게 하긴 했는데 꾸미는건 pass...


🔍  input 상태 관리하기

input 태그는 리액트에서 사용자가 입력 할 수 있게 해주는 태그

 

InputSample 컴포넌트 코드임다

  • useState 사용
  • input 받아주는 값을 나타내는 text의 초깃값 ''로 설정
  • input값이 바뀌는 이벤트 발생시 text도 바뀜 (value : input으로 받은 내용)
  • 이벤트 객체 'e' e.target은 이벤트가 발생한 DOM( input DOM)을 가르킴
  • 초기화 클릭시 text를 ''로 초기화
  • 이후로는 위에서 배운거랑 똑같이 해줬습니다~~~~

이건 결과물

 

🔍  여러개의 input 상태 관리하기

 

  • 모든 input 값을 하나의 객체로 관리하고
  • 공통된 onChange 함수로 처리하는 방식이 효율적이다.
import React, { useState } from 'react';

function InputSample() {
    const [inputs,setInputs] = useState({
    name: '',
    nickname: ''
});

    const { name, nickname } = inputs; 
    	// 아래 두 줄이 자동으로 생긴 셈
	//const name = inputs.name;
	//const nickname = inputs.nickname;

    const onChange = (e) => {
        const { value, name } = e.target;

        setInputs({
            ...inputs,
            [name]: value
            
        });
    };

    const onReset = () => {
        setInputs({
            name: '',
            nickname: '',
        })
    };

    return(
        <div>
            <input name="name" placeholder="이름" onChange={onChange} value={name}/>
            <input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname} />
            <button onClick={onReset}>초기화</button>
            <div>
                <b>값: </b>
                {name} ({nickname})
            </div>
        </div>
    );
}

export default InputSample;

 

  • useState를 사용 하기위해 inputs : 입력 받은 값을 담는 객체, setInputs : 상태 업데이트 하는 함수, 초기값으로 name 과 nickname이 ''인 객체
  •  구조 분해 할당을 이용해서 inputs 객체에서 name, nickname 값을 꺼냄
  • 내용이 바뀌었을 때 이벤트 처리 (마찬가지로 구조 분해 할당으로 e.target에서 name, value추출)
  • ...inputs : 전개 연산자(Spread Operator)를 사용한 것 (기존 상태 복사해서 유지하면서 일부만 바꾸기)
  • inputs[name] = value 이런식으로 기존 상태를 직접 수정하게 되면, 값을 바꿔도 리렌더링이 되지 않음
  • setInput에서 바뀐 값만 수정
  • 초기화 클릭시 내용 초기화 이벤트 처리
  • 화면에 출력
spread 문법

 

  • 위에서 사용한 ... 문법  -객체의 내용을 모두 "펼쳐서" 기존 객체를 복사
  • 이러한 작업을 "불변성을 지킨다"라고 한다.
  • 불변성을 지켜주어야만 리액트 컴포넌트에서 상태가 업데이트가 됐음을 감지 할 수 있고 이에 따라 필요한 리렌더링이 진행

이렇게 끝.............!!!!!!!!!!!!

 

미리 해놨으니 이제 놀겠습니다 ㅋㅋ

 

반응형