본문 바로가기

[React] 정리

728x90

와이파이가 없어서 한글에 정리해놓은건데 잃어버릴 수 있으니까 여기에다가 올려놔야겠다 ㅎㅎ

 

 

 

React JS

#1. 강의소개

- create-react-app을 이용해 functional component 작성법과 JSX를 배움

- React Hook(useState, useEffect)도 함께 다룸

CRUD 구현을 위해 JSON-Server를 띄우고 Rest API를 통신하며 단어들을 추가(POST), 수정(PUT), 삭제(DELETE)하는 작업

 

=> 강의를 듣기 전 node.js(프레임워크),VSCode(텍스트 에디터) 설치, htmljavaScript 지식

 

 

#2. 설치

적당한 폴더를 만들어 cmd창 띄우기

npx create-react-app 프로젝트명

 

npx: npm에 올라가 있는 패키지를 바로 실행해서 설치시켜주는 도구

 

VSCode에서 폴더 열기

터미널 열어서 해당 프로젝트 이름으로 이동(cd 프로젝트명) npm start

 

 

node_modules는 이 프로젝트를 실행할 때 사용되는 dependencies 모듈들이 모두 모여있음(package.json에서 볼 수 있음)-> 폴더를 지우면 프로젝트를 띄울 수 없음, 폴더를 지우더라도 package.json파일만 수정되지 않았다면 npm install 해주면 그대로 다시 설치 가능

(크기가 굉장히 크고 파일도 많기 때문에 node_modules 폴더는 git에 올리지 않음)

 

public 폴더 내에 index.html 파일에 있는 <div id = “root”></div>로 리액트 코드가 실행돼서 만들어진 DOM이 구현되게 된다.

 

index.js 파일을 보면 App.js 파일을 불러오는 부분을 볼 수 있음(import App from ‘.App’;)

id rootApp을 렌더링 시켜준다(

ReactDOM.render(

<React.StrictMode>

<App/>

<React.StrictMode>,

document.getElementById(‘root’)

);).-> index.html에 있던 root

 

 

App.js에서 구현하면 됨(여기서 뭔가를 작성하거나 수정하면 브라우저에 바로 반영(Hot Module Replacement(HMR)).

컨트롤 C를 누르면 프로젝트가 내려가고, npm start로 다시 띄울 수 있음

(명령어는 package.json 파일에 명시)

 

start는 개발 모드로 프로그램 실행

build는 실제 배포 모드로 만들어줌

test는 테스트

eject는 내부 설정 파일을 꺼내는 역할(웹페이지나 바벨(?) 설정을 변경하고 싶을 때 사용)

 

App.js를 보면 class가 자바스크립트의 예약어라 className

JSX는 자바스크립트 내부에 HTML처럼 작성하는 것

 

 

#3. 컴포넌트, JSX

리액트로 만든 페이지는 컴포넌트들로 구성되어 있다. 페이지 단위로 HTML을 작성하는 것이 아니라 각 부분을 컴포넌트로 만들어 조립해서 사용(비슷한 부분들은 코드를 재사용할 수 있고, 유지보수도 쉬어짐)

 

function App(){} -> 함수로 만들어진 앱 컴포넌트(함수형 컴포넌트)

-> 이 함수가 리턴하는 것은 JSX(JavaScript XML)

이거를 index.js에서 import해서 사용

모든 컴포넌트는 대문자로 시작해야 함

 

 

 

function App() {

const name = "Tom"

return (

<div className="App">

<h1

style={{

color:"red",

backgroundColor:"green"

}}>

Hello, {name}.

<p>{2 + 3}</p>

</h1>

</div>

);

}

- backgroundColor 같은 경우에는 로 연결해주는 것이 아닌 대문자로 구분해주는 카멜 케이스(Camel case)로 작성

- {} 내부에서 변수명 사용

- 문자열이나 숫자는 잘 나오지만 boolean 타입이나 객체는 표현하지 못함

function App() {  

  const name ="Tom";

  const user = {

    name:"Jane",

  };

  return (

    <div className="App">

      <h1

        style={{

          color:"red",

          backgroundColor:"green",

        }}>

        Hello, {name}.

        <p>{user}</p>

      </h1>

    </div>

  );

}

-> 이런 식으로 user 객체를 만들고 실행하면 오류

 

 

function App() {

const name = "Tom";

const naver = {

name: "네이버",

url: "https://naver.com",

};

return (

<div className="App">

<h1

style={{

color:"red",

backgroundColor:"green",

}}>

Hello, {name}.

<p>{2 + 3}</p>

</h1>

<a href={naver.url}>{naver.name}</a>

</div>

);

}

-> 객체를 만들어 링크를 만들었음

 

 

#4. 첫 컴포넌트 만들기

컴포넌트라는 폴더를 만든다.

js파일과 함수 만들고 export 해주면 컴포넌트를 만들 수 있음(항상 대문자로 시작)

 

const Hello = function(){

return <p>Hello</p>

}

export default Hello;

 

또는

 

const Hello = () => {

return <p>Hello</p>

}

export default Hello;

 

또는

 

export default function Hello(){

return <p>Hello</p>;

}

 

 

 

 

 

App.jsimport

import Hello from './component/Hello'; -> .js는 빼고 적어도 됨

 

function App() {

return <div className="App">

<Hello></Hello>

</div>

}

-> 이런 식으로 쓰는데 태그 안에 아무것도 적는 것이 없으면

function App() {

return <div className="App">

<Hello />

</div>

}

->셀프 크로즈해주는 것이 좋음

 

 

 

 

import World from "./World";

 

export default function Hello(){

return (

<div>

<h1>Hello</h1>

<World />

</div>

);

}

-> div 태그가 없으면 오류가 남(JSX는 하나의 태그만 만들 수 있기 때문)

 

한 번 만들어놓은 컴포넌트는 계속해서 재사용할 수 있다!!

 

 

 

#5. CSS 작성법(module css)

create-react-app으로 만든 프로젝트라면 별도의 다른 패키지 설치 없이 사용할 수 있는 방법 3가지

인라인 스타일(css 파일을 따로 작성할 필요 없이 html 태그에 바로 작성)

스타일 안은 {}를 한 번 더 작성해서 객체로 만들어야 함

객체이기 때문에 세미콜론(;)이 아니라 쉼표(,)

데쉬(-)가 아닌 카멜 케이스로 작성(대문자로 구분)

속성값은 문자열이면 따옴표로 감싸줘야 함

숫자는 그냥 숫자를 써도 되지만 픽셀 같은 것은 따옴표로 감싸줘야 함

 

import World from "./World";

 

export default function Hello(){

return (

<div>

<h1 style={{

color : '#f00',

borderRight : '12px solid #000',

marginBottom : '50px',

opacity : 1,

}}

>

Hello

</h1>

<World />

<World />

</div>

);

}

-> 특별한 이유가 없으면 인라인으로 작성하지 않음

 

 

 

2. css 파일 활용(class를 추가하며 사용할 수 있음)

index.css는 전체 프로젝트에 영향을 미침

App.cssApp 컴포넌트에 한정된 내용들이 들어가 있음

-> css 파일들이 각 컴포넌트에 종속되는 것이 아닌 헤드 부분에 다 작성되기 때문에 전 페이지(맨 처음 적용한 것)에 다 영향을 미치게 됨

 

 

 

3. 각 컴포넌트에 특화된 css를 작성(css module 활용)

파일명은 보통 컴포넌트의 이름에 맞춰적어줌(Hello.module.css)

Hello.jsimport 해줄 때는 styles-> import styles from "./Hello.module.css";

className을 적어줄 때는 {styles.~~}로 적기-> <div className={styles.box}>Hello</div>

 

 

-> 동일한 내용을 작성하더라도 서로 중복될 일이 없음(css 파일이 커지면 가장 고민되는 것이 네이밍이랑 상속, 오버라이딩에 대한 부분인데, 이 방식으로 말끔하게 해결할 수 있음)

글로벌 단위가 아닌 컴포넌트 단위로 관리되는 것이 장점

 

 

그냥 index.css에 작성한다 함

 

 

 

 

VSCode 단축키 정리

단축키 명령 설명
ctrl+d 다음 선택 블록 선택 후 입력 시 같은 다음 블록이 중복 선택
ctrl+x 행 삭제(빈 선택) 커서의 1행 삭제
ctrl+s 저장 현재 파일 저장
ctrl+alt+s 모두 저장 열린 파일 모두 저장
ctrl+\ 편집기 나누기 편집창 분할
ctrl+숫자 편집창 이동 입력된 숫자의 편집창으로 이동
ctrl+k ctrl+왼쪽 왼쪽 편집창으로 이동 왼쪽 편집창으로 이동(ctrl+k누른 후, ctrl+왼쪽 방향 키 누름)
ctrl+k ctrl+오른쪽 오른쪽 편집창으로 이동 오른쪽 편집창으로 이동(ctrl+k누른 후, ctrl+오른쪽 방향 키 누름)
shift+alt+Down 위에 행 복사 추가 위에 행 복사 추가
shift+alt+Up 아래 행 복사 추가 아래 행 복사 추가
ctrl+shift+Enter 위에 행 삽입 커서 위에 행 삽입
ctrl+g 행 이동 입력된 라인 넘버의 행으로 이동
F12 정의로 이동 정의로 이동
shift+F12 참조 표시 해당 function을 사용하고 있는 부분 표시
shift+Alt+F/전체 선택 후 ctrl+K+F: 자동 정렬
 

 

 

#6. 이벤트 처리(Handling Events)

- 이벤트를 거는 첫 번째 방법

미리 함수를 만들어놓고 전달

button의 속성으로 onClick은 카멜 케이스로 작성해주고 전달하고자 하는 내용은 문자열이 아니기 때문에 {}

 

export default function Hello(){

function showName(){

console.log("Mike");

}

return (

<div>

<h1>Hello</h1>

<button onClick={showName}>이름 보이기</button>

<button>나이 보이기</button>

</div>

);

}

-> 만약 showName()이라고 써주면 반환하는 값을 출력해주기 때문에 (지금은 반환되는 값이 없으니)undefined가 들어가게 됨

 

두 번째 방법

onClick 내부에 직접 함수 구현

export default function Hello(){

function showName(){

console.log("Mike");

}

return (

<div>

<h1>Hello</h1>

<button onClick={showName}>이름 보이기</button>

<button onClick={()=>{

console.log(30);

}}

>

나이 보이기

</button>

</div>

);

}

 

------------------------

export default function Hello(){

function showName(){

console.log("Mike");

}

function showAge(age){

console.log(age);

}

return (

<div>

<h1>Hello</h1>

<button onClick={showName}>이름 보이기</button>

<button onClick={()=>{

showAge(10);

}}

>

나이 보이기

</button>

</div>

);

}

 

-> (매개변수를 전달하기 편함)

----------------------------------------

 

export default function Hello(){

function showName(){

console.log("Mike");

}

function showAge(age){

console.log(age);

}

function showText(e){

console.log(e.target.value);

}

 

return (

<div>

<h1>Hello</h1>

<button onClick={showName}>이름 보이기</button>

<button onClick={()=>{

showAge(10);

}}

>

나이 보이기

</button>

<input type="text" onChange={showText}/>

</div>

);

}

 

바뀔 때마다 찍혀야 되니까 onChange를 써줌

showTexte(이벤트 객체)로 받음

tagetinput 태그가 됨

valueinput의 값이니까 작성한 값

 

== 위의 코드와 동일함

export default function Hello(){

function showName(){

console.log("Mike");

}

function showAge(age){

console.log(age);

}

 

return (

<div>

<h1>Hello</h1>

<button onClick={showName}>이름 보이기</button>

<button onClick={()=>{

showAge(10);

}}

>

나이 보이기

</button>

<input type="text" onChange={(e)=>{

console.log(e.target.value)

}}/>

</div>

);

}

==위의 코드와 동일함

export default function Hello(){

function showName(){

console.log("Mike");

}

function showAge(age){

console.log(age);

}

function showText(txt){

console.log(txt);

}

 

return (

<div>

<h1>Hello</h1>

<button onClick={showName}>이름 보이기</button>

<button onClick={()=>{

showAge(10);

}}

>

나이 보이기

</button>

<input

type="text"

onChange={e=>{

const txt = e.target.value;

showText(txt);

}}/>

</div>

);

}

 

 

#7. state, useState (상태값)

state 컴포넌트가 갖고 있는 상태값(상태값이 변하면 리액트는 자동으로 UI를 업데이트)

 

export default function Hello(){

let name = "Mike"

 

function changeName(){

name = name === "Mike" ? "Jane" : "Mike";

console.log(name);

//바닐라스크립트로 작업을 한다면 DOM 업데이트 작업을 하기 위해 다음 코드 추가

document.getElementById("name").innerText = name;

}

 

return (

<div>

<h1>state</h1>

<h2 id="name">{name}</h2>

<button onClick={changeName}>바꾸기</button>

</div>

);

}

 

-> id“name”elementtextname으로 바꿔주고 있음

여기서 namestate가 아니라 변수임(이 컴포넌트가 관리하고 있는 상태값이 아님) -> 바뀌어도 리액트는 인지하지 못하고 UI를 업데이트하지 못한다.

 

 

 

 

 

 

 

어떻게 하면 state로 만들 수 있을까?

->첫 번째 리액트인 useState를 사용한다.

 

리액트 16.8부터 모든 컴포넌트를 함수형으로 만들 수 있게 되었고, 리액트 Hook을 이용해 함수형 컴포넌트에서도 statelifecycle 관리가 가능해짐

 

 

 

 

useState(상태값 관리)

import {useState} from "react";

 

export default function Hello(){

//let name = "Mike";

const [name, setName] = useState('Mike');

 

function changeName(){

const newName = name === "Mike" ? "Jane" : "Mike";

//document.getElementById("name").innerText = name;

setName(newName);

}

 

return (

<div>

<h1>state</h1>

<h2 id="name">{name}</h2>

<button onClick={changeName}>바꾸기</button>

</div>

);

}

 

.................. 이렇게 작성해도 됨

function changeName(){

setName(name === "Mike" ? "Jane" : "Mike");

}

.................

 

 

또는

 

import { useState } from "react";

 

export default function Hello() {

//let name = "Mike";

const [name, setName] = useState('Mike');

 

return (

<div>

<h1>state</h1>

<h2 id="name">{name}</h2>

<button

onClick={() => {

setName(name === "Mike" ? "Jane" : "Mike");

}}

>

바꾸기

</button>

</div>

);

}

 

 

 

const [name, setName] = useState('Mike');//구조 분해 할당

useState는 배열을 반환하는데 첫 번째 값은 state(name..변수명이라 생각하면 됨)이고 두 번째는 이 state를 변경해주는 함수(setName이 호출돼서 name이 바뀌면 리액트는 이 컴포넌트(Hello)를 다시 렌더링 해줌)

useState()()안에는 초기값을 넣어주면 됨

 

 

 

Hello 컴포넌트를 App3번 그리면 동일한 컴포넌트라도 state는 각각 관리됨(다른 state에 영향을 주지 않음)

#8. props

App.js
import './App.css';
import Hello from './component/Hello';


function App() {
return (
<div className="App">
<h3>props : properties</h3>
<Hello age={10} />
<Hello age={20} />
<Hello age={30} />
</div>
);
}


export default App;

 

Hello.js
import { useState } from "react";


export default function Hello(props) {
const [name, setName] = useState('Mike');


return (
<div>
<h2 id="name">
{name}({props.age})</h2>
<button
onClick={() => {
setName(name === "Mike" ? "Jane" : "Mike");
}}
>
바꾸기
</button>
</div>
);
}

 

props(properties(속성값)의 약자): 이 값은 컴포넌트 내부에서 변경할 수 없음(넘겨받은 그대로 사용)-> 값을 변경하고 싶으면 컴포넌트 내부에서 state를 다시 만들어야함

Hello.js
import { useState } from "react";


export default function Hello(props) {
const [name, setName] = useState('Mike');
const [age, setAge] = useState(props.age);


return (
<div>
<h2 id="name">
{name}({age})</h2>
<button
onClick={() => {
setName(name === "Mike" ? "Jane" : "Mike");
setAge(age + 1);
}}
>
바꾸기
</button>
</div>
);
}

-> 넘겨받은 값을 변경하고 있는 것이 아닌 해당 컴포넌트에서 만든 age가 바뀌는 것임

 

 

 

age만 나오니까 다음과 같이 바꿔줄 수 있음(자바스크립트: 구조 분해 할당)
import { useState } from "react";


export default function Hello({ age }) {
const [name, setName] = useState('Mike');


return (
<div>
<h2 id="name">
{name}({age})</h2>
<button
onClick={() => {
setName(name === "Mike" ? "Jane" : "Mike");
}}
>
바꾸기
</button>
</div>
);
}

 

 

프롭스로 정보를 받고 이용하는 예

import { useState } from "react";


export default function Hello({ age }) {
const [name, setName] = useState('Mike');
const msg = age > 19 ? "성인 입니다." : "미성년자 입니다.";


return (
<div>
<h2 id="name">
{name}({age}) : {msg}
</h2>
<button
onClick={() => {
setName(name === "Mike" ? "Jane" : "Mike");
}}
>
바꾸기
</button>
</div>
);
}

 

 

 

화면에 어떤 데이터를 갱신하기 위해서 stateprops를 사용해 처리하는 것이 좋음

 

 

- 한 컴포넌트가 가지고 있는 stateprops로 넘기기

UserName.js
export default function UserName({name}){
return <p>Hello, {name}</p>
}

 

Hello.js
import { useState } from "react";
import UserName from "./UserName";


export default function Hello({ age }) {
const [name, setName] = useState('Mike');
const msg = age > 19 ? "성인 입니다." : "미성년자 입니다.";


return (
<div>
<h2 id="name">
{name}({age}) : {msg}
</h2>
<UserName name={name} />
<button
onClick={() => {
setName(name === "Mike" ? "Jane" : "Mike");
}}
>
바꾸기
</button>
</div>
);
}

-> 파란부분에서 nameHello 컴포넌트에서는 state이지만 UserName 컴포넌트 입장에서는 props

 

 

#9. 더미 데이터 구현, map() 반복문

API가 없는 상태이기 때문에 더미 데이터를 하나 만들어서 사용

 

 

 

날짜와 단어를 배열로 만들고 정보들을 입력

 

 

 

 

만든 더미 데이터를 불러오기(Daylist.js)

liday 개수만큼 그려줘야하는데 반복문을 사용해야함 -> map(배열을 받아서 또 다른 배열을 반환->이때 반환되는 요소는 JSX로 작성)을 사용하는게 편함

key는 반복되는 요소의 고유한 값을 넣어줘야함(id)

 

import dummy from "../db/data.json";


export default function DayList(){
console.log(dummy);
return <ul className="list_day">
{dummy.days.map(day => (
<li key={day.id}>Day {day.day}</li>
))}


</ul>;
}

특정 날짜에 단어들이 나오는 페이지(Day.js)-> 단어들이 쭉 나오니까 테이블로 구현

import dummy from "../db/data.json";


export default function Day(){
//dummy.word
const day = 1;
const wordList = dummy.words.filter(word => word.day===day);
console.log(wordList);
return<>
<table>
<tbody>
{wordList.map(word => (
<tr key={word.id}>
<td>{word.eng}</td>
<td>{word.kor}</td>
</tr>
))}
</tbody>
</table>
</>;
}

 

 

 

 

다음 시간은 페이지 이동, 라우팅

# 10. 라우터 구현(react-router-dom)

주소로 /를 하면 첫 페이지로 이동


 

728x90

'' 카테고리의 다른 글

[강의] 학습중...  (0) 2024.04.24
[인프런] 기초 HTML  (0) 2024.03.30
[인프런] 웹 개발 시작해봐요  (0) 2024.03.18