#오늘 배운 것
function Todo(props){
return <div>{props.todo}</div>
}
자식 컴포넌트를 받을 때 props를 사용하는 모든 곳에서 props. 를 붙여줘야만 했다.
다만 js 구조 분해 할당을 이용하면 생략이 가능하다.
//중괄호{} 안에 객체 key name을 적으면 된다.
function Todo({ title }){
return <div>{title}</div>
}
defaultProps,
부모 컴포넌트에서 props를 보내주지 않아도 설정될 초기 값.
prop중에서는 자주 받거나 무조건 받아야하는 props가 있는데 부모 컴포넌트가 props를 주기 전에 defaultProps를 이용하고 부모 컴포넌트에서 props가 내려오면 내려받을 props로 바뀌게 된다.
// 이렇게 설정합니다.
Child.defaultProps={
name: '기본 이름'
}
// 구조 분해 할당 문법을 사용하면 이렇게도 할 수 있어요.
function Child({ name = '기본이름' }){
return <div>내 이름은 {name} 입니다. </div>
}
State
컴포넌트 내부에서 바뀔 수 있는 값
if const에 있는 value값을 고정이 아닌 계속 변경해줘야 한다면 그 때 사용하는것이 state다
State를 만들 때는 useState()를 사용
Q.let이라는 변수로 선언해줘도 되는데 왜 state로 선언하는가?
A. 컴포넌트의 lifecycle이라는 화면 값이 변했을 때 이 값을 다시 렌더링해줘야 하는 조건이 있다.
그 조건 중 하나가 state가 변경됐을 때다.그러므로 화면에 바로 반영하려면 state를 써야함.
//usestae를 통해 state를 선언한다.
const [ value, setValue ] = useState( 초기값 )
//setValue는 state를 변경할 때 사용하는 함수. 이 함수를 사용해야만 state변경이 가능하다.
//새로고침하면 다시 초기값으로 변경된다.
먼저 const 로 선언을 하고 [ ] 빈 배열 을 생성하고, 배열의 첫번째 자리에는 이 state의 이름, 그리고 두번째 자리에는 set 을 붙이고 state의 이름을 붙입니다. 그리고 useState( ) 의 인자에는 이 state의 원하는 처음값 을 넣어줍니다.
state를 변경할때는 setValue(바꾸고 싶은 값) 를 사용한다.
Hook
기존에 사용하던 Class를 이용한 코드를 작성할 필요 없이,
state와, 여러 React 기능을 사용할 수 있도록 만든 라이브러리
useState + onClick Event
state 구현하고 이벤트 핸들러와 연결
이벤트핸들러로 컴포넌트와 함수를 연결한다
state를 하나 만든다(버튼을 클릭을 했을 때 state 값을 바꾼다) -> 이벤트 핸들러를 만들어주고 그 안에 setName 을 넣어준다. ->이제 버튼을 누르면 setName()안에 있는 값 "길동이"에서 “누렁이”로 바뀐다.
function App() {
const [name, setName] = useState("길동이");
function onClickHandler() {
setName("누렁이");
}
return (
<div>
{name}
<button onClick={onClickHandler}>버튼</button>
</div>
);
}
Input과 state 구현하기
input에서는 보통 사용자가 입력한 값을 state로 관리하는 패턴을 많이 사용합니다.
input에 onChange라는 이벤트를 불러내고 -> 생성한 이벤트 핸들러 함수를 넣습니다.
여기서 사용한 event객체는 dom html객체이다.
const App = () => {
const [value, setValue] = useState("");
const onChangeHandler = (event) => {
//사용자가 입력한 input값을 추출하기 위해event.target.value에 접근.
const inputValue = event.target.value;
//이후 추출한 값을 setValue의 state에 연결하면 input과 연결된다.
setValue(inputValue);
};
return (
<div>
//사용자가 input의 값을 입력하면 그 때마다(onchange) value인 setValue를 해서 값을 넣는다.
<input type="text" onChange={onChangeHandler} value={value} />
</div>
);
};
불변성이란?
메모리에 있는 값을 변경할 수 없는 것. 변수가 메모리에 저장되는 방식과 연관성이 있다.ex) 자바스크립트의 데이터 형태중에 원시 데이터는 불변성이 있고, 원시 데이터가 아닌 객체, 배열, 함수는 불변성 없습니다.
원시 데이터는 값을 수정 했을 때 기존 메모리가 아닌 새로운 메모리를 교체하는 것이고, 원시 데이터가 아닌 것은 기존 메모리에서 값을 수정한 것.
React의 경우 화면을 리렌더링 할지 말지 정할 때 state 변화를 확인한다.
state가 변했는지 변하지 않았는지 확인하는 방법이 state의 변화 전, 후의 메모리 주소를 비교한다.
만약 리액트에서 원시데이터가 아닌 데이터를 수정할 때 불변성을 지켜주지 않고, 직접 수정을 가하면 값은 바뀌지만 메모리주소는 변함이 없게 되는것
//배열에 setState를 할 때 전개연산자...를 통해 기존값을 복사하고 추가하거나 수정한다.
function App() {
const [dogs, setDogs] = useState(["말티즈"]);
function onClickHandler() {
// spread operator(전개 연산자)를 이용해서 dogs를 복사합니다.
// 그리고 나서 항목을 추가합니다.
setDogs([...dogs, "시고르자브르종"]);
}
컴포넌트
리액트의 핵심 빌딩 블록
DOM (명령형 프로그래밍)
명령형으로 작성된 코드의 경우 Hello, World!를 출력하기 위해 컴퓨터가 수행하는 절차를 일일히 코드로 작성해주어야한다.
리액트 (선언형 프로그래밍)
화면에 어떻게 그려야할지는 React 내부에 잘 숨겨져 추상화되어 있다.
// React 코드 (선언적인)
const header = <h1>Hello World</h1>; // jsx
ReactDOM.render(header, document.getElementById('root'));
렌더링
컴포넌트가 현재 props와 state의 상태에 기초하여 UI를 어떻게 구성할지 컴포넌트에게 요청하는 작업
쉽게 이해하기 위해 예시를 들어본다.
- UI - 음식
- 컴포넌트 - 음식을 만드는 주방장
- 리액트 - 주문받고 서빙하는 웨이터
-
- 렌더링 일으키는 것은 (triggering) - 손님이 UI를 주문하고 주방으로 전달하는 것
- 렌더링한다는 것은 (rendering)- 주방에서 컴포넌트가 UI를 만들고 준비하는 것
- 렌더링 결과는 실제 DOM에 커밋한다는 것은 (commit) - 리액트가 준비된 UI를 손님 테이블에 올려놓는 것

리액트 앱이 실행되고 첫 렌더링이 일어나면 리액트는 컴포넌트의 루트에서 시작하여 아래쪽으로 쭉 훑으며 컴포넌트가 반환하는 JSX 결과물을 DOM 요서에 반영한다.(자동)
첫 렌더링을 끝난 이후에 추가로 렌더링을 트리거 하려면 상태를 변경해주면된다.
컴포넌트 상태에 변화가 생기면 리렌더링이 발생합니다. 이때 여러 상태가 변경됐다면 리액트는 이를 큐(queue)자료구조에 넣어 순서를 관리합니다.
- 주방 예시를 다시 들어보면 리렌더링은 음식점 손님이 첫 주문 이후에 갈증이 생겨 추가로 음료를 주문하거나 처음 받은 음식이 마음에 들지 않아 새로운 메뉴를 주문하는 것과 같습니다. == 새로운 주문(ui)
- 새로운 UI주문(리렌더링)이 일어나면 리액트가 변경된 내용을 주방에 있는 요리사인 컴포넌트에 전달하고 컴포넌트는 새로운 변경된 주문을 토대로 새로운 요리(UI)를 만듭니다.
- 새롭게 만들어진 요리(렌러딩 결과)는 리액트에 의해 다시 손님 테이블에 올려집니다(DOM에 반영 - commit phase).

브라우저 렌더링
렌더링이 완료되고 React가 DOM을 업데이트한 후 브라우저는 화면을 그립니다. 이 프로세스를 "브라우저 렌더링"이라고 하지만 혼동을 피하기 위해 "페인팅"이라고도 합니다
count 만들기
import React, { useState } from "react";
function App() {
const [number, setNumber] = useState(0); //초기값 0
return (
<div>
{number}
<buttononClick={() => {setNumber(number + 1);}}>+</button>
<buttononClick={() => {setNumber(number - 1);}}>-</button>
</div>
);
} //익명함수를 사용한 방법
export default App;
CSS 분리없이 한번에 처리하기
const App = () => {
const style = {
padding: "100px",
display: "flex",
gap: "12px",
}; //바탕
const squaryStyle = {
width: "100px",
height: "100px",
border: "1px solid green",
borderRadius: "10px",
display: "flex",
alignItems: "center",
justifyContent: "center",
}; //네모
return (
<div style={style}>
<div style={squaryStyle}>감자</div>
<div style={squaryStyle}>고구마</div>
<div style={squaryStyle}>오이</div>
</div>
);
};
컴포넌트 파일에서 CSS 코드 분리하기 -> app.js파일을 css와 jsx파일로 나눈다.(js와 jsx파일 둘다 사용가능)
import "./App.css"; //css파일 연결하고,
const App = () => { //CSS class를 className에 붙여넣기
return (
<div className="app-style">
<div className="squaryStyle">감자</div>
<div className="squaryStyle">고구마</div>
<div className="squaryStyle">오이</div>
</div>
);
};
// -> 이 코드의 문제점 : 같은 코드가 중복되고,개발자가 직접 타이핑해야한다.
//그리고 추가시 수기로 작성해서 다시 배포해야한다.
//이 때 사용하는 것이 map()이다.
map()
JSX에서 map() 은 배열의 모든 요소를 순회함.
const App = () => {
const vet = ["감자","고구마","오이"]
return (
<div className="app-style">
{vet.map((vegetableName) =>{
return(
<div className="square-style" key={vegetableName}>
{vegetableName}
</div>
)
})}
</div>
);
};
//위의 코드를 배열로수정한 코드
import React, { useState } from "react";
import "./App.css";
//1. 버튼 컴포넌트 생성
function CustomButton(props) {
//props로 onclick을 받았고,children은 버튼사이의 값을 children으로받는다.
const { color, onClick, children } = props;
if (color) {
//무조건 color가 있는 코드를 만든다면 if문은 딱히 안써도 됨.
return (
<button style={{ background: color, color: "white" }} onClick={onClick}>
{children}
</button>
);
}
return <button onClick={onClick}>{children}</button>;
}
function User(props) {
return (
<div className="squaryStyle">
{props.user.age}살 - {props.user.name}
<CustomButton
color="red"
onClick={() => props.handleDelete(props.user.id)}
>
삭제하기
</CustomButton>
</div>
);
}
const App = () => {
const [users, setUsers] = useState([
{ id: 1, age: 30, name: "송중기" },
{ id: 2, age: 24, name: "송강" },
{ id: 3, age: 21, name: "김유정" },
{ id: 4, age: 29, name: "구교환" },
]);
const [name, setName] = useState(""); // <-- 유저의 입력값을 담을 상태
const [age, setAge] = useState("");
const addUserHandler = () => {
const newUser = {
id: users.length + 1, //유저의 길이를 추가한다. 지금 유저가 4이니 새유저가되면 5가되도록하는 것.
age: age,
name: name,
};
setUsers([...users, newUser]); //배열을 만들었고,기존 user배열을 스프레드문법으로 풀었고,기존 user배열에 추가했다.
};
const deleteUserHandler = (id) => {
//삭제할 id를 받는다.
const newUserList = users.filter((user) => user.id !== id);
//filter를 이용해서 각각의 유저에서 내가 설정한 아이디와 같지 않으면 새로운 유저리스트배열을 추가해라.
setUsers(newUserList);
};
return (
// 중괄호->user의 map을 돌림 -> 각 유저에 화살표 함수로 유저 컴포넌트를 리턴해라
// -> 그리고 각각의 유저의 props를 넘긴다.->그리고 key라는 것을 보낸다.
// 나이와 이름을 렌더링하니 user가 props로 배열안에 긴 객체 값을 받아야한다.*
<div>
<div className="app-style">
{users.map((user) => {
return (
<User handleDelete={deleteUserHandler} user={user} key={user.id} />
);
})}
</div>
<input
value={name}
placeholder="이름을 입력해주세요"
// 인풋 이벤트로 들어온 입력 값을 name의 값으로 업데이트
onChange={(e) => setName(e.target.value)}
/>
<input
value={age}
placeholder="나이를 입력해주세요"
// 인풋 이벤트로 들어온 입력 값을 age의 값으로 업데이트
onChange={(e) => setAge(e.target.value)}
/>
<CustomButton color="green" onClick={addUserHandler}>
추가하기
</CustomButton>
</div>
//app-style컴포넌트 안에 user가 map으로 돌면서 user안에있는 정보를 props로 넘긴다
//그럼 user에 props를 위의 squaryStyle에 받아 이름과 나이를 출력
);
};
export default App;
key :
리액트에서 map을 사용하여 컴포넌트를 반복 렌더링 할 때는 반드시 컴포넌트에 key를 넣어줘야 합니다
key가 필요한 이유는 React에서 컴포넌트 배열을 렌더링했을 때 각각의 원소에서 변동이 있는지 알아내려고 사용하기 때문입니다. 만약 key가 없다면 React는 가상돔을 비교하는 과정에서 배열을 순차적으로 비교하면서 변화를 감지하려 합니다. 하지만 key가 있으면 이 값을 이용해서 어떤 변화가 일어났는지 더 빠르게 알아낼 수 있게 됩니다. 즉, key값을 넣어줘야 React의 성능이 더 최적화 된다. 라는 의미입니다.
key는 props처럼 생겼지만 props로 설정하지 않아도 key는 넣을 수 있다.
예시에서 age가 25이상인 user는 제외하고 렌더링
map() 안에서도 조건식을 사용 할 수 있습니다.
age가 25 미만인 user는 User 컴포넌트를 이용해 화면에 렌더링 해주고, 그것이 아닐 때는 화면에 아무것도 렌더링 하지 않기 위해 null 을 return 합니다. null 이란, 값이 “없음”을 개발자가 의도적으로 표현하는 데이터 형태이자 값 입니다.
return (
<div style={style}>
{users.map((user) => {
if (user.age < 25) {
return <Square user={user} key={user.id} />;
} else {
return null;
}
})}
</div>
Compiled with problems: Module not found: Error: Can't resolve
★오류 발생 : 컴포넌트 파일을 분리 후 갑자기 오류가 발생했다..export랑 import도 제대로 했는데 왜지...
구글링으로는 js 파일 가져올 때 파일의 경로가 잘못되었다는 뜻입니다 라는데...왜..

-> 알고보니 src 주소를 추가해서 그런것이였다. 초반에는 src빼도 안됐었는데 왜 이랬지...
Vercel
Vercel은 AWS 와 같은 클라우트 컴퓨팅 서비스를 제공하는 서비스
단지 깃헙과 연동하고, 소스를 push 를 할때 마다 새로운 소스코드가 자동으로 배포도 됩니다. 또한 SSL 설정도 자동으로 적용이 되며, custom domain도 아주 쉽게 연결할 수 있습니다.
깃허브 레포지토리 생성 및 remote 등록
Vercel로 들어갑니다. 그리고 깃허브 아이디를 이용해서 로그인 ->
Overview 화면으로 이동됩니다. 우측 상단에 New Project 버튼을 클릭

-> Import Git Repository 라는 메뉴에 우리가 아까 생성한 레포지토리가 보입니다. 그것을 import
->그리고 Deploy 버튼을 클릭 이후 STATUS가 ready 라면 배포가 완료된 것이다.

'[내일배움캠프] > TIL' 카테고리의 다른 글
| 22.12.08)React숙련 배운 29일차 (0) | 2022.12.08 |
|---|---|
| 22.12.07)react과제를 한 28일차 (1) | 2022.12.07 |
| 22.12.05)React와 es6, 후발대 2일차를 배운 26일차 (0) | 2022.12.05 |
| 22.12.02)CS특강과후발대1일차를 배운 25일차 (0) | 2022.12.02 |
| 22.12.01)this -call apply,callback, dom을 배운 24일차 (1) | 2022.12.01 |