1. 리액트는 어쩌다 만들어졌을까?
사용자와의 인터랙션이 자주 발생
➡️ 처리해야 할 이벤트, 관리해야 할 상태값, DOM이 다양해지게 되고 규칙도 많이 복잡해짐
➡️ Ember, Backbone, AngularJS 등의 프레임워크가 만들어짐
* 이 프레임워크들은 자바스크립트의 특정 값이 바뀌면 특정 DOM의 속성이 바뀌도록 연결해서 업데이트
💡 상태가 바뀌었을 때, 아예 처음부터 새로 만들어서 보여주자는 아이디어에서 리액트가 시작
❓ 근데 이러면 속도가 매우 느리게 되지 않나?? 그래서 리액트에서는 Virtual DOM을 사용함
* 브라우저에 보여지는 DOM이 아닌 메모리에 가상으로 존재하는 DOM으로, JavaScript 객체이기 때문에 속도가 훨씬 빠름
즉, DOM의 상태를 메모리에 저장하고, 변경 전과 후의 상태를 비교한 뒤 최소한의 내용만 반영하는 것
Virtual DOM의 동작 원리
UI가 변경 감지 ➡️ UI를 Virtual DOM으로 렌더링(실제 화면이 아닌 가상 렌더링)
➡️ 이전과 현재 Virtual DOM을 비교해 차이 계산
➡️ 변경된 부분을 실제 DOM에 반영
❓ 만약 Virtual DOM이 없으면 ?
DOM은 변경된 빨간 부분뿐만 아니라 모든 동그라미들을 빨간색으로 바꿔서 렌더링함, 사소한 변경에도 전체가 리렌더링돼 비효율적
2. 작업환경 준비
❗️ 설치해야 할 것 ❗️
Node.js, Yarn, 코드 에디터(VSCode, WebStorm 등), Git Bash(윈도우의 경우에만 설치)
새 프로젝트 만들어보기(터미널에 작성)
// react-study 디렉터리 안에 리액트 프로젝트 생성
$ npm create-react-app react-study
$ cd react-study
$ npm start
3. 나의 첫번째 리액트 컴포넌트
src 내부에 Hello.js 파일을 만들고 아래 코드를 작성하고, App.js도 아래와 같이 수정해주세요
- 리액트 컴포넌트를 만들 땐
import React from 'react;
를 통해 리액트를 불러와줘야 함
- 컴포넌트를 내보내줘야 다른 컴포넌트에서 불러와서 사용할 수 있음
export default Hello;
id 가 'root'인 DOM을 선택하고 있는데 이 DOM은 public/index.html 안에 <div id="root"></div>에 있음
즉, 리액트 컴포넌트가 렌러딩될 때, 이 결과물이 위 div 내부에 렌더링되는 것
4. JSX
- JSX는 리액트에서 생김새를 정의할 때 사용하는 문법
* Babel https://bit.ly/2wMpkk2
Babel · Babel
The compiler for next generation JavaScript
babeljs.io
: 자바스크립의 문법을 확장해주는 도구,
리액트 컴포넌트 파일에서 XML 형태로 코드를 작성하면 babel이 JSX를 JavaScript로 변환해줌
- JSX 규칙
1. 태그는 꼭 닫혀있어야 함 ex) <div></div>
* Self Closing 태그: 바로 닫히는 태그, 태그와 태그 사이에 내용이 들어가지 않을 때 사용
ex) <input />, <br />
2. 두개 이상의 태그는 무조건 하나의 태그로 감싸져있어야 함
* Fargment: 태그를 이름없이 작성하면 만들어짐, div 같은 걸로 감싸기 애매할 때 사용
3. JSX 안에 자바스크립트 값 사용하기
JSX 내부에 자바스크립트 변수를 보여줘야할 때에는 {} 으로 감싸서 보여줌
4. style과 className
인라인 스타일 ➡️ 객체 형태로 작성
- 로 구분되어 있는 이름 ex) backgrount-color ➡️ camelCase 형태로 네이밍 ex) backgroundColor
5. 주석
JSX 내부 주석은 {/* 이런 형태로 */} 작성
열리는 태그 내부에서는 // 이런 형태로도 작성
5. props(properties)를 통해 컴포넌트에게 값 전달하기
App 컴포넌트 -- (name, color 이라는 값 전달) --> Hello 컴포넌트
- 컴포넌트에게 전달되는 props는 파라미터를 통해 조회, 객체 형태로 전달됨
- 코드를 간결하게 작성하기 위해서는 비구조화 할당 문법 사용 (Hello 컴포넌트에 props 대신에 {color, name} 전달)
- 컴포넌트에게 props를 지정하지 않았을 때 defaultProps 라는 값 설정
// Hello.js에 추가
Hello.defaultProps = {
name: "이름 없음"
}
- props.children
: 컴포넌트 태그 사이에 넣은 값을 조회하고 싶을 때 사용
6. 조건부 렌더링
: 특정 조건에 따라 다른 결과를 렌더링하는 것 (삼항연산자 사용)
* && 연산자: 단순히 특정 조건이 true, false 일 경우 삼항연산자 대신 사용
// isSpecia이 true일 때 <b>**</b>
{isSpecial && <b>**</b>}
- props 값 설정을 생략하면, true로 설정한 것으로 간주
7. useState 를 통해 컴포넌트에서 바뀌는 값 관리하기
- 리액트 패키지에서 useState 라는 함수 불러오기
import React, {useState} from 'react';
- 첫 번째 함수는 현재 상태, 두 번째 원소는 Setter 함수
: useState 함수를 통해 컴포넌트에서 상태를 관리할 수 있음
const [number, setNumber] = useState(0);
- useState를 통해 Counter 컴포넌트 만들어보기
* on이벤트이름 = {실행하고싶은함수} ex) onClick = {onIncrease} → 이때, 함수형태를 넣어줘야 함 onClick = {onIncrease()} ❌
8. input 상태 관리하기
- onChange 이벤트
이벤트 객체 e를 차라미터로 받아와서 e.target을 통해 이벤트가 발생한 DOM을 가르킴
이 DOM의 value 값 (e.target.value) 를 조회하면 input에 입력한 값을 알 수 있음
9. 여러개의 input 상태 관리하기
* placeholder: input이 비어져있을 때 이 input에 대한 설명을 보여줌
- spread 문법 (... 문법)
: 객체의 내용을 모두 "펼쳐서" 기존 객체를 복사해줌 (불변성을 지킨다)
* 불변성일 지켜주어야만 리액트 컴포넌트에서 상태가 업데이트 됐음을 감지할 수 있고 이에 따라 필요한 리렌더링이 진행됨
setInputs({
...inputs,
[name]: value
});
- 리액트에서 객체를 업데이트하게 될 때에는 기존 객체를 직접 수정하지 않고 새로운 객체를 만들어서, 새 객체에 변화를 주어야 함
inputs[name] = value 과 같이 기존 객체를 직접 수정하면, 값은 바꿔도 리렌더링 ❌
📝 과제 📝
- 과제: 자기소개 카드 만들기
- 조건 1. 이름, 나이, 취미를 Props로 전달받아 출력
- 조건 2. 버튼 클릭 시 좋아하는 음식을 변경하도록 State를 사용해 구현
import React, { useState } from 'react';
import styled from "styled-components";
const Wrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100vh;
background-color: #fef3f7;
`;
const Box = styled.div`
background-color: #ffffff;
width: 300px;
padding: 20px;
border-radius: 16px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
font-family: 'Helvetica', sans-serif;
font-size: 16px;
color: #333;
`;
const Label = styled.div`
margin-bottom: 8px;
line-height: 1.6;
`;
const Input = styled.input`
width: 80%;
padding: 8px;
margin-top: 4px;
margin-bottom: 12px;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 14px;
outline: none;
transition: border 0.2s;
&:focus {
border-color: #ee7ea0;
}
`;
const Button = styled.button`
padding: 8px 16px;
background-color: #ee7ea0;
color: white;
border: none;
border-radius: 8px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.3s;
&:hover {
background-color: #e4608c;
}
`;
function Card({ name, age, hobby }) {
const [value, setValue] = useState('');
const onChange = (e) => {
setValue(e.target.value);
}
const onClick = () => {
setValue('');
}
return (
<Wrapper>
<Box>
<Label>이름: {name}</Label>
<Label>나이: {age}</Label>
<Label>취미: {hobby}</Label>
<Label>좋아하는 음식: {value}</Label>
<Input onChange={onChange} value={value} placeholder="좋아하는 음식이 먼가요" />
<Button onClick={onClick}>변경</Button>
</Box>
</Wrapper>
)
}
export default Card;
'WINK-(Web & App) > React.js 스터디' 카테고리의 다른 글
[2025 1학기 React.js 스터디] 이종민 #3주차 (0) | 2025.04.10 |
---|---|
[2025 1학기 React.js 스터디] 최은희 #3주차 (0) | 2025.04.10 |
[2025 1학기 React.js 스터디] 한혜민 #3주차 (1) | 2025.04.09 |
[2025 1학기 React.js 스터디] 정채은 #3주차 (0) | 2025.04.09 |
[2025 1학기 React.js 스터디] 강민지 #3주차 (0) | 2025.04.09 |