가수면
React 입문 본문
프로젝트 생성하기
yarn create react-app (폴더명)
※ yarn 또는 npx. 경로 설정하지 않으면 사용자 폴더가 기본 경로로 설정됨.
https://kim-oriental.tistory.com/14
[Node.js 개발환경] Node.js 및 VS code 설치, Node.js 초기 프로젝트 생성 및 실행
안녕하세요, 윈도 OS 환경에서 Node.js (노드js) 및 VS code (Visual Studio Code, 비주얼 스튜디오 코드) 설치 후, VS Code에서 Node.js 프로젝트 생성 및 실행에 대해 포스팅하도록 하겠습니다. Node.js 설치 먼저,
kim-oriental.tistory.com
프로젝트 다운받기
다른 react 파일을 받을 경우 => yarn install 또는 npm install
실행
터미널 -> yarn start (npx로 했을 경우 npm start)
중괄호 사용
JSX 문법 안에서 자바스크립트 값을 가져오려면 중괄호를 사용해야 함
const cat_name = 'perl';
return (
<div>
# 중괄호여야만 함
hello {cat_name}!
</div>
);
function App() {
const number = 1;
return (
<div className="App">
<p>안녕하세요! 리액트 반입니다 :)</p>
{/* JSX 내에서 코드 주석은 이렇게 씁니다 :) */}
{/* 삼항 연산자를 사용했어요 */}
<p>{number > 10 ? number+'은 10보다 크다': number+'은 10보다 작다'}</p>
</div>
);
}
class 대신 className
<div className="App">
인라인으로 style 주기
# 중괄호를 두 번 쓰는 이유? 딕셔너리도 자바스크립트니까요!
# 이렇게 쓰거나,
<p style={{color: 'orange', fontSize: '20px'}}>orange</p>
# 혹은 스타일 딕셔너리를 변수로 만들고 쓸 수 있어요!
function App() {
const styles = {
color: 'orange',
fontSize: '20px'
};
return (
<div className="App">
<p style={styles}>orange</p>
</div>
);
}
컴포넌트
컴포넌트는 한 개의 태그만 리턴 값으로 설정할 수 있음(단 한 개의 루트 JSX 요소를 가져야 함)
예) div 태그가 3개였기에 하나로 묶어줌.
return (
<div className='expense-date'>
<div className='expense-date__yeat'>{year}</div>
<div className='expense-date__month'>{month}</div>
<div className='expense-date__day'>{day}</div>
</div>
);
사용자 지정 컴포넌트는 className을 사용할 수 없음
return (
<Card className='expense-item'>
사용하고자 한다면 아래와 같이 상수를 선언하고 들어갈 태그 사이에 {props.children} (래퍼 컴포넌트를 생성하게 됨)을 넣어줌..
function Card(props) {
const classes = 'card ' + props.className;
return (<div className={classes}>{props.children}</div>);
}
※ 'card ' 처럼 띄어쓰기 한 칸 해준 이유
Card.css 파일에 스타일이 적용되어 있는 클래스의 이름이 card 인데, card뒤에 띄어쓰기 없이 쓰면 클래스네임이cardexpenses가 되어 CSS스타일이 적용되지 않음.
그러나 띄어쓰기를 해주면 className="card expenses" 가 되므로, 해당 div에 .card 의 스타일과 .expenses의 스타일이 반영됨
props
부모 컴포넌트로부터 받아온 데이터.
연결고리 역할을 해준다고 생각하면 됨. props를 활용하면 <CourseGoalItem> 안에 있는 태그에도 원하는 값을 넣을 수 있게 되어 컴포넌트가 된다.
import React from "react";
function App() {
return <GrandFather />;
}
function GrandFather() {
const name = '할아버지'
return <Mother GrandFather={name} />;
}
function Mother(props) {
return <Child GrandFather={props.GrandFather} />;
}
function Child(props) {
return <div>{props.GrandFather}</div>;
}
export default App;
props는 오직 부모 컴포넌트에서 자식 컴포넌트로만 전달할 수 있다.
props는 가독성을 위한 약속일 뿐, 변수명처럼 아무렇게나 지어줘도 된다.
예)
function Mother(props) {
return <Child GrandFather={props.GrandFather} />;
}
function Child(aaa) {
return <div>{aaa.GrandFather}</div>;
}
심화
App 컴포넌트에서는 ExpenseItem 컴포넌트를 사용
import ExpenseItem from "./components/ExpenseItem";
function App() {
.
.
.
return (
<div>
<h2>Let's get started!</h2>
<ExpenseItem
title={expenses[0].title}
amount={expenses[0].amount}
date={expenses[0].date}
/>
ExpenseItem 컴포넌트 안에서는 ExpenseDate 컴포넌트를 사용
function ExpenseItem(props) {
return (
<div className='expense-item'>
<ExpenseDate date={props.date} />
<div className='expense-item__description'>
<h2>{props.title}</h2>
<div className='expense-item__price'>{props.amount}원</div>
</div>
</div>);
<ExpensDate>뿐만 아니라 props의 도움으로 props.title이라든지 props.amount 등의 데이터를 보냄.(ExpenseItem에서 데이터의 일부를 출력)
date는 이미 props를 통해 받고 다시 props를 사용해 더 안쪽에 있는 ExpenseDate 컴포넌트로 보내짐
state
import React, { useState } from 'react';
function GrandFather() {
const [name, setName] = useState("김할아"); // 이것이 state!
return <Mother grandFatherName={name} />;
}
prop을 섞어서 응용
import React, { useState } from "react";
function Child(props) {
return <div>{props.grandFatherName}</div>;
}
function Mother(props) {
return <Child grandFatherName={props.grandFatherName} />;
}
function GrandFather() {
const [name, setName] = useState("김할아"); # state를 생성
return <Mother grandFatherName={name} />;
}
function App() {
return <GrandFather />;
}
export default App;
State 변경하기
import React, { useState } from "react";
function Child(props) {
return (
<div>
<button
onClick={() => {
props.setName("박할아");
}}
>
할아버지 이름 바꾸기
</button>
<div>{props.grandFatherName}</div>
</div>
);
}
function Mother(props) {
return (
<Child grandFatherName={props.grandFatherName} setName={props.setName} />
);
}
function GrandFather() {
const [name, setName] = useState("김할아");
return <Mother grandFatherName={name} setName={setName} />;
}
function App() {
return <GrandFather />;
}
export default App;
useState, props, map 섞어서 응용
import React, { useState } from "react";
import "./App.css"; // 🔥 반드시 App.css 파일을 import 해줘야 합니다.
function CustomButton(props) {
const { color, onClick, children } = props
if (color) {
return <button
style={{ backgroundColor: color, color: 'white' }}
onClick={props.onClick}>{children}</button>
}
return <button onClick={props.onClick}>{children}</button>
}
function User(props) {
return (
<div className='square-style'>{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,
age: age,
name: name
}
setUsers([...users, newUser])
}
const deleteUserHandler = (id) => {
const newUserList = users.filter((user) => user.id !== id);
setUsers(newUserList)
}
return <div>
<div className="app-style">
{users.map((user) => {
if (user.age < 25) {
return (<User handleDelete={deleteUserHandler} user={user} key={user.id}></User>)
} else {
return null;
}
})}
</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>;
};
export default App;
함수형 setState
// 일반 업데이트 방식 -> 100번이든 1000번이든 한번만 실행
<button
onClick={() => {
setNumber(number + 1); // 첫번째 줄
setNumber(number + 1); // 두번쨰 줄
setNumber(number + 1); // 세번째 줄
}}
>
// 함수형 업데이트 방식 -> 쓴 만큼 실행
<button
onClick={() => {
setNumber((previousState) => previousState + 1);
setNumber((previousState) => previousState + 1);
setNumber((previousState) => previousState + 1);
}}
>
React에서 상태가 변경되면, 해당 변경 사항은 다음 렌더링 주기에서 반영된다. 즉, 상태를 변경하면 컴포넌트는 다시 렌더링되고, 변경된 상태가 새로운 렌더링에서 적용된다. 변경된 상태는 다음 렌더링 주기에서 컴포넌트의 렌더링 결과에 반영된다.
간혹 상태값이 바뀌었음에도 반영되지 않았던 이유가 바로 이것이다.
오토배칭의 부작용이라고 할 수도 있을 것 같다.
컴포넌트 분리
js파일 만들어서 컴포넌트 잘라넣고 끝에 아래 코드 입력
export default 컴포넌트명
메인 js파일 위에 붙여줌.
import 컴포넌트명 from "경로";
화면에 console이 두 번씩 찍히는 이유
프로젝트의 src/index.js에서 <React.StrictMode> 태그로 <app/>이 감싸져있으면개발모드에서 (개발 단계시 오류를 잘 잡기위해) 두 번씩 렌더링됨.
즉, strict mode(엄격 모드) 때문임
'React > React' 카테고리의 다른 글
useEffect (0) | 2022.12.02 |
---|---|
props 비구조화 할당 (0) | 2022.12.01 |
동적 렌더링 (0) | 2022.11.29 |
state 끌어올리기 (0) | 2022.11.28 |
props (0) | 2022.11.27 |