[리액트의 특징]
- 컴포넌트를 기반으로 UI를 표현한다.
- 화면 업데이트 구현이 쉽다.
- 화면 업데이트가 빠르게 처리된다.
[컴포넌트를 기반으로 UI를 표현한다.]
컴포넌트 - 화면을 구성하는 요소, UI를 구성하는 요소
각각의 JAVASCRIPT 파일로 모듈화하여 레고 블록처럼 만들 수 있음 ⇒ 중복 코드를 재사용 가능!
페이지의 모든 요소를 컴포넌트화하여 생성 → 이후 불러와서 사용
[화면 업데이트 구현이 용이]
업데이트란? 사용자의 행동(클릭, 드래그)에 따라 웹 페이지가 스스로 모습을 바꿔 상호작용 하는 것
렌더링? UI 요소를 화면에 그려내는 것을 말함
선언형 프로그래밍 : 과정은 생략하고 목적만 간결히 명시하는 방법 ex) 식당에 가서 주문하는 것처럼 “토마토 파스타 하나 주세요” 처럼 말하고 토마토 파스타 만드는 방법은 알 필요가 없음
명령형 프로그래밍 : 목적을 이루기 위한 모든 일련의 과정을 설명하는 방식
ex) 마치 진상 손님처럼 주문하고 토마토 파스타 만드는 방법을 일일히 명시하여야 하기 때문
[화면 업데이트가 빠르게 처리된다]
가상의 DOM의 각각의 업데이트를 처리하고 1번에 실제 DOM에 반영을 하기에 렌더링이 빠름!
React App 생성하기
기본설정이 이미 완료된 React App 생성 툴
React 공식 문서에서도 권장되고 있음
[Vite 설치 순서]
- npm create vite@latest
- Project name 입력
- 진행할 프레임워크 설치 → React
- 사용할 언어 선택
- 이후 생성한 project 폴더 명이 Root 폴더가 되도록 설정
- 이후 npm i로 터미널 창에 입력하고 필요한 모듈을 설치
- public 폴더 내부
- svg, png, jpg 와 같은 이미지 파일이거나 font 혹은 동영상 등 코드가 아닌 정적인 파일 저장소
- src 폴더 내부
- 실제 react 및 javscript 코드를 작성할 폴더
- assets 폴더 내부
- svg, png, jpg 와 같은 이미지 파일 저장소
- index.html 파일
- 리액트 앱의 기본 틀을 역할을 하는 html 코드 정보
[npm run dev]
"no-unused-var": "off",
"react/prop-types": "off",
"no-unused-var": "off":
설명: JavaScript에서 사용되지 않은 변수를 경고하는 규칙인 no-unused-var를 끕니다. 즉, 사용하지 않은 변수가 있어도 경고하지 않도록 설정한 것입니다.
"react/prop-types": "off":
설명: React 컴포넌트에서 prop-types로 전달되는 props의 타입을 명시하지 않아도 경고하지 않도록 하는 설정입니다. 보통 prop-types는 props의 타입을 명확하게 하기 위해 사용되지만, 이 규칙을 끄면 타입을 명시하지 않아도 문제가 되지 않습니다.
따라서 이 두 설정은 ESLint가 사용하지 않은 변수를 허용하고, React에서 prop-types 사용에 대한 경고를 무시하도록 만든 것입니다.
---eslint.config.js----
import js from '@eslint/js'
import globals from 'globals'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
export default [
{ ignores: ['dist'] },
{
files: ['**/*.{js,jsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
settings: { react: { version: '18.3' } },
plugins: {
react,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...js.configs.recommended.rules,
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
...reactHooks.configs.recommended.rules,
'react/jsx-no-target-blank': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
//아래 코드 복사!
"no-unused-var": "off",
"react/prop-types": "off",
},
},
]
TailwindCSS 설치 방법 in Vite : https://tailwindcss.com/docs/guides/vite
[React App의 구동 원리]
http://localhost:5173 : 자신의 컴퓨터를 의미(포트번호 :5173)
→ localhost는 자신의 컴퓨터에만 작동하게 되므로 다른 사람의 컴퓨터에는 작성되지 않습니다!
createRoot(document.getElementById('root')).render(
index.html에 나와 있는 내용을 불러오는 역할
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx' -> Root 파일
import './index.css' -> css 파일 속성
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
)
-- App.jsx --
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
-- index.html --
😎[React 컴포넌트] - 반드시 대문자로 생성
App.jsx 컴포넌트 내부에 components를 불러 오게 되면
App 컴포넌트가 부모(조상) 컴포넌트 (즉, Root 컴포넌트 - 관례상 App 사용!)
App 컴포넌트에 import하는 컴포넌트는 자식 컴포넌트 (함수 컴포넌트의 return 값을 설정)
만약, 이렇게 main.jsx 에서 <App />을 <Hello />로 변경하게 되면 루트 컴포넌트는 Hello가 되는 것!
📍여기서 한 파일명.jsx 에 전부 작성하기 보다는 컴포넌트별로 파일을 만들어 import 하여 불러오는 형식으로 작성하는 것을 권장합니다.
컴포넌트를 만들 때, src 하위 "component" 파일 내부에 파일명.jsx를 작성!
[JSX란?] - 리액트에서 사용하는 확장된 자바스크립트 문법
[JSX 주의 사항]
숫자 및 문자열 값이면 { } 객체 데이터 내부에 만들어서 렌더링 하도록 만들 수 있음
1. 중괄호 { } 내부에는 자바스크립트 표현식만 넣을 수 있다.
→ 한 줄로 표현이 가능한 식들 가능 / 😎if문 혹은 for문은 1줄로 표현이 되지 않기에 중괄호 내부에 들어갈 수 없음
2. 숫자, 문자열, 배열 값만 렌더링 된다.
ex) bolean , undefined, null 값은 화면에 렌더링 되지 않습니다. ex) true, undefined,null,obj... 등
😎여기서 객체 값은 렌더링 되지 않아 {obj.a} 등 객체 데이터 내부에 문자 및 숫자값으로 변경하여야 합니다.
코드를 입력하다 렌더링되는 브라우저화면이 백지로 나타나게 되는 것은 오류가 발생한 것!
3. 모든 태그는 닫혀 있어야 한다.
4. 최상위 태그는 반드시 하나여야만 한다. ( <> ~ </> [Tip, 빈태그로 묶고 시작]
이렇듯, 최상위 태그가 <main> ~ </main> 태그와 <div> ~ </div> 태그 이렇게 2가지가 존재할 경우 오류가 발생하게 됩니다.
따라서, 최상위 태그는 <main> ~ </main>로 작성하여야 합니다.
만약, 최상위 태그가 필요없을 경우 <> ~ </> 처럼 빈태그로 반환하면 됩니다.
const App = () => {
const user = {
name: "전용학",
isLogin: true,
};
if (user.isLogin) {
return <div>로그아웃</div>;
} else {
<div>로그아웃</div>;
}
// return <>{user.isLogin ? <div>로그인</div> : <div>로그아웃</div>}</>;
};
export default App;
객체 내부에 로그인을 구현하도록 설정!
[JSX에서 style을 설정하는 방법 - 2가지 방법이 존재]
style={{
backgroundColor: “red”,
borderBottom: "5px solid blue",
}}
- style속성을 지정할 때, 기존에 작성한 css 형식인 background-color가 아닌 backgroundColor 이렇게 카멜 케이스로 작성해야 함! [반드시 {{}} 이렇게 중첩하여 작성해야 함!]
- 별도의 css 파일을 만들어 css 작성하기
.logout {
background-color: red;
border-bottom: 5px solid green;
}
Main.css(임의의 파일)을 작성하고 App.jsx에서 import “./Main.css”를 입력하고 나서
태그 내부 속성에 className=”logout” 이라고 작성하면 됩니다.
[Props - 컴포넌트에 값 전달하기]
이렇게 하나의 Button 컴포넌트를 만들어서 image와 text만 바꾸어서 반복 렌더링하여 구성하는 기능
😎props란 부모 컴포넌트로부터 자식 컴포넌트에 데이터를 보낼 수 있게 해주는 방법이다.
const Button = (props) => {
console.log(props);
return (
<>
<button style={{ color: props.color }}>
{props.text} - {props.color.toUpperCase()}
</button>
</>
);
};
Button.defaultProps = {
color: "black",
};
export default Button;
--Button.jsx---
여기서 Button 컴포넌트에 text와 color
속성을 지정하고 나서 1번째 버튼요소를 제외한 2,3번째는
color 속성이 없기 때문에 이럴때는, Button.defaultProps =
{ } 내부에 color의 기본값을 지정하여 오류가 발생하지 않
도록 방지함!
😎 defaultProps에서는 부모 컴포넌트로부터 props를 전달하려고 할 때, 전달하고자 하는 속성이 undefined일 때를 방지하여 전달하고자 하는 컴포넌트명.defaultProps로 지정하고 = { 내부에 undefined 대신 작성할 속성을 정의하는 형태}
언제 따옴표를 사용해야 하나?
- 문자열 값: color, fontFamily, backgroundColor 등과 같이 색상, 글꼴, 단위가 있는 값은 문자열로 작성해야 합니다. 예를 들어 color: "black", fontSize: "16px", fontFamily: "Arial"처럼 문자열로 작성합니다.
- 숫자 값: opacity, zIndex, flex 등 단위가 없는 숫자형 값은 문자열로 작성하지 않아도 됩니다. 예를 들어, opacity: 0.5, zIndex: 10, flex: 1처럼 숫자로 바로 작성할 수 있습니다.
import Header from "./components/Header";
import Main from "./components/Main";
import Footer from "./components/Footer";
import Button from "./components/Button";
const App = () => {
return (
<>
<Header />
<Main />
<Footer />
<Button text={"메일"} color={"red"} />
<Button text={"카페"} />
<Button text={"블로그"} />
</>
);
};
export default App;
---App.jsx---
props - 객체 형태 { “” }로 전달 받는다는 것을 앎 - 비구조화 할당 방법을 통한 Props 전달
import Header from "./components/Header";
import Main from "./components/Main";
import Footer from "./components/Footer";
import Button from "./components/Button";
const App = () => {
const buttonProps = {
a: 1,
b: 2,
c: 3,
};
return (
<>
<Header />
<Main />
<Footer />
<Button {...buttonProps} text={"메일"} color={"red"} />
<Button text={"카페"} />
<Button text={"블로그"} />
</>
);
};
export default App;
다음과 같이 값을 전달할 내용이 여러 개일 경우 배열로 만들
어 a:1, b:2, c:3 이렇게 작성하고 ... 전개연산자로 객체 형식
으로 불러오면 됩니다.
😎 props에서 값은 부모 컴포넌트에서 자식 컴포넌트로만 전달 가능! / 반대는 React에서 불가능함
import "./App.css";
import Header from "./components/Header";
//파일의 확장자는 Header.jsx를 작성하지 않아도 vite가 알아서 찾아가도록 설정해줌!
import Button from "./components/Button";
function App() {
const buttonProps = {
text: "메일",
color: "red",
a: 1,
b: 2,
c: 3,
};
return (
<>
<Button {...buttonProps} />
<Button text={"카페"} />
<Button text={"블로그"}>
<div>자식요소</div> => 이렇게 prps로 전달할 컴포넌트에 자식 컴포넌트가 존재할 경우 children
</Button>
<h1>안녕 리액트!</h1>
</>
);
}
export default App;
😎children은 부모 컴포넌트에서 정의된 컴포넌트 내부에 또 다른 자식 요소를 중첩하고 싶을 때 사용됩니다.
[이벤트 핸들링]
onClick = {onClickHandler} 이렇게 속성을 작성합니다.
/* eslint-disable react/prop-types */
const Button = ({ text, color, children }) => {
const onClickHandler = () => {
console.log({ text });
};
return (
<>
<button onClick={onClickHandler} onMouseEnter={onClickHandler}>
{text} - {color.toUpperCase()}
{children}
</button>
</>
);
};
Button.defaultProps = {
color: "black",
};
export default Button;**
[이벤트 객체] (e) ⇒ { } / 공식 문서: https://react.dev/learn/responding-to-events
합성 이벤트 - 모든 웹 브라우저의 이벤트 객체를 하나로 통일한 형태
이벤트 사용 시 주의사항
1. 이벤트 이름은 😎카멜표기법으로 작성
HTML에서는 onclick으로 작성하지만 리액트에서는 카멜 표기법으로 onClick으로 작성해야한다
2. 이벤트에는 😎함수 형태의 값을 전달
HTML에서 이벤트를 설정할 때 ""안에 실행할 코드를 넣었지만, 리액트에서는 함수 형태의 객체를 전달한다. 애로우(화살표)함수 문법을 사용하거나 혹은 외부에 미리 함수를 만들어서 전달하기도한다.
3. 😎DOM요소에만 이벤트를 설정할 수 있다.
div, button, input, form, span 등의 DOM요소에는 이벤트를 설정할 수 있지만, 직접만든 리액트 컴포넌트에는 이벤트를 자체적으로 설정할 수 없다.
이러한 Cross Browsing Issue를 해결하는 방법이 합성 이벤트
[State - 상태 관리하기]
이렇듯, 하나의 컴포넌트 안에 여러 개의 state를 작성할 수 있습니다.
const [state, setState] = useState();
const [현재 값, 현재 값을 변경시키는 함수] = useState(초기값);
또한, const [ state, setState] = useState(" ")에서 userState값에 “ ” 혹은 0 등 기본값을 작성하지 않으면 화면에 렌더링이 되지 않을 수 있습니다. 따라서, 상태 초기값을 명시적으로 설정하는 것을 권장합니다.
리액트가 Re-rendering 되는 3가지 상황
- 자신이 관리하는 state의 값이 변경되었을 때
- 자신이 제공받은 props의 값이 변경되었을 때
- 부모 컴포넌트가 리렌더링 되었을 때, 자식 컴포넌트도 리렌더링 됨
import { useState } from "react";
const Bulb = () => {
const [light, setLight] = useState("");
return (
<>
<div>
{light === "ON" ? (
<h1 style={{ backgroundColor: "orange" }}>ON</h1>
) : (
<h1 style={{ backgroundColor: "gray" }}>OFF</h1>
)}
<button
onClick={() => {
setLight(light === "ON" ? "OFF" : "ON");
}}
>
{light === "ON" ? "끄기" : "켜기"}
</button>
</div>
</>
);
};
const Counter = () => {
const [count, setCount] = useState(0); // 초기값 설정
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
};
const App = () => {
return (
<>
<Bulb />
<Counter />
</>
);
};
export default App;
이렇게 컴포넌트를 나누게 되면 화면에는 리렌더링 되는 상황을 방지하여 더 빠르게 상태를 업데이트 할 수 있습니다.
→ 이 컴포넌트를 Bulb.jsx 와 Counter.jsx로 파일로 분리하여 모듈화하여 사용하는 것을 권장합니다.
[State로 사용자 입력 관리하기]
📍이벤트 함수를 사용할 때 반드시 사용해야 할 것
(e) ⇒ set함수명(e.target.value)
onChange={onChangeCountry} 와 value={country} 반드시 2개의 필수 요소를 작성해야 합니다.
onChange 이벤트 함수 : onchange 이벤트는 HTML 요소의 값이 변경될 때 발생하는 이벤트입니다. 이 이벤트는 주로 <input>, <select>, <textarea>와 같은 폼 요소에서 많이 사용됩니다. 값이 변경되면 이벤트 핸들러를 호출하여 특정 작업을 수행할 수 있습니다.
e.preventDefault()
기본(default)를 막다(prevent)라는 단어에서 유추할 수 있듯이 html에서 표준으로 제공하는 태그의 기본 이벤트 발생을 막는 메서드입니다.
e.preventDefault(); // 폼 제출 시 페이지 리로드를 방지
사용 예시:
- 링크 클릭 시 페이지 이동을 막고, 대신 자바스크립트로 다른 동작을 수행하고 싶을 때.
- 폼 제출 시 페이지가 새로고침되지 않도록 하고, AJAX로 데이터를 처리하고 싶을 때.
e.stopPropagation()
전파(Propagation)를 중지한다(stop)라는 의미처럼 상위 엘리먼트로의 이벤트 전파(이벤트 버블링)을 막기 위한 메서드입니다.
사용 예시:
- 중첩된 요소에서 하위 요소의 이벤트가 상위 요소에 전달되지 않도록 하고 싶을 때.
- 버튼 클릭 시 하위 요소에서만 특정 동작을 하고, 상위 요소는 무시하고 싶을 때
// 간단한 회원가입 폼
// 1. 이름
// 2. 생년월일
// 3. 국적
// 4. 자기소개
import { useState } from "react";
const Register = () => {
const [name, setName] = useState("이름");
const onChangeName = (e) => {
setName(e.target.value);
// onChangeName의 인자로 이벤트를 전달하면 전달한 이벤트
의 값으로 상태를 변경토록 해주는 로직
};
return (
<div>
<input onChange={onChangeName} type="text" placeholder="이름" />
{name} // props로 사용자의 입력값에 따라 변동
</div>
);
};
export default Register;
이벤트 부분에서 (e) ⇒ setName(e.target.value)에서 작성하게 되면 div 태그 내부에서 input
리액트의 useState를 이용하여 사용자의 입력 값을 저장하고 처리할 때에는 onChange 속성과 더불어 value={ } 속성까지 사용하여야 합니다.
// 간단한 회원가입 폼
// 1. 이름
// 2. 생년월일
// 3. 국적
// 4. 자기소개
import { useState } from "react";
const Register = () => {
const [name, setName] = useState("이름");
const [birth, setBirth] = useState("");
const onChangeBirth = (e) => {
setBirth(e.target.value);
};
const onChangeName = (e) => {
setName(e.target.value);
};
return (
<div>
<div>
<input
value={name}
onChange={onChangeName}
type="text"
placeholder="이름"
/>
</div>
<div>
<input value={birth} onChange={onChangeBirth} type="date" />
</div>
</div>
);
};
export default Register;
이렇게 작성하게 되면 날짜를 선택하게 되면 상태 값이 저장 되는 것을 볼 수 있습니다. {birth} 값을 추가하여 나타나게 되면
이렇게 나타나게 할 수 있습니다.
// 간단한 회원가입 폼
// 1. 이름
// 2. 생년월일
// 3. 국적
// 4. 자기소개
import { useState } from "react";
const Register = () => {
const [name, setName] = useState("이름");
const [birth, setBirth] = useState("");
const [country, setCountry] = useState("");
const onChangeCountry = (e) => {
setCountry(e.target.value);
};
const onChangeBirth = (e) => {
setBirth(e.target.value);
};
const onChangeName = (e) => {
setName(e.target.value);
};
return (
<div>
<div>
<input
value={name}
onChange={onChangeName}
type="text"
placeholder="이름"
/>
</div>
<div>
<input value={birth} onChange={onChangeBirth} type="date" />
</div>
{birth}
<div onChange={onChangeCountry} value={country}>
<select>
{/* select 태그에 빈 태그를 추가하려면 바로 아래처럼 아무것도 입력하지 않으면 됩니다. */}
<option value=""></option>
{/* 이렇게 설정하게 되면 만약 한국을 선택할 때, 상태 값은 kr로 나오고 한국으로 나오지 않습니다. */}
<option value="kr">한국</option>
<option value="us">미국</option>
<option value="uk">영국</option>
<option value="gr">독일</option>
<option value="fr">프랑스</option>
<option value="ita">이탈리아</option>
</select>
{country}
</div>
</div>
);
};
export default Register;
여기서 option 태그에 value 값으로 kr, us 등 간격하게 지정하게 해 놓고 사용자 화면에는 한국이면 상태 값은 kr로 업데이트 되도록 하는 형식이 좋습니다.
// 간단한 회원가입 폼
// 1. 이름
// 2. 생년월일
// 3. 국적
// 4. 자기소개
import { useState } from "react";
const Register = () => {
const [name, setName] = useState("이름");
const [birth, setBirth] = useState("");
const [country, setCountry] = useState("");
const [bio, setBio] = useState("");
const onChangeBio = (e) => {
setBio(e.target.value);
};
const onChangeCountry = (e) => {
setCountry(e.target.value);
};
const onChangeBirth = (e) => {
setBirth(e.target.value);
};
const onChangeName = (e) => {
setName(e.target.value);
};
return (
<div>
<div>
<input
value={name}
onChange={onChangeName}
type="text"
placeholder="이름"
/>
</div>
<div>
<input value={birth} onChange={onChangeBirth} type="date" />
</div>
{birth}
<div onChange={onChangeCountry} value={country}>
<select>
{/* select 태그에 빈 태그를 추가하려면 바로 아래처럼 아무것도 입력하지 않으면 됩니다. */}
<option value=""></option>
{/* 이렇게 설정하게 되면 만약 한국을 선택할 때, 상태 값은 kr로 나오고 한국으로 나오지 않습니다. */}
<option value="kr">한국</option>
<option value="us">미국</option>
<option value="uk">영국</option>
<option value="gr">독일</option>
<option value="fr">프랑스</option>
<option value="ita">이탈리아</option>
</select>
{country}
</div>
<div>
<textarea onChange={onChangeBio} value={bio} placeholder="자기소개">
{bio}
</textarea>
{bio}
</div>
</div>
);
};
export default Register;
위에 작성한 내용이 동작하는 방식이 동일하여 1개의 state로 작성하도록 만들려면 아래와 같이 작성하여야 합니다.
**// 간단한 회원가입 폼
// 1. 이름
// 2. 생년월일
// 3. 국적
// 4. 자기소개
import { useState } from "react";
const Register = () => {
const [input, setInput] = useState({
name: "",
birth: "",
country: "",
bio: "",
});
const onChangeBio = (e) => {
setInput({
...input,
bio: e.target.value,
});
};
const onChangeCountry = (e) => {
setInput({
...input,
country: e.target.value,
});
};
const onChangeBirth = (e) => {
setInput({
...input,
birth: e.target.value,
});
};
const onChangeName = (e) => {
setInput({
...input, // name값을 제외한 나머지 값들을 변경하지 않을 상태로 나타냄
name: e.target.value, // 변경하고자하는 props의 값만 바꾸어야 됨
});
};
return (
<div>
<div>
<input
value={input.name}
onChange={onChangeName}
type="text"
placeholder="이름"
/>
</div>
<div>
<input value={input.birth} onChange={onChangeBirth} type="date" />
</div>
{input.birth}
<div onChange={onChangeCountry} value={input.country}>
<select>
{/* select 태그에 빈 태그를 추가하려면 바로 아래처럼 아무것도 입력하지 않으면 됩니다. */}
<option value=""></option>
{/* 이렇게 설정하게 되면 만약 한국을 선택할 때, 상태 값은 kr로 나오고 한국으로 나오지 않습니다. */}
<option value="kr">한국</option>
<option value="us">미국</option>
<option value="uk">영국</option>
<option value="gr">독일</option>
<option value="fr">프랑스</option>
<option value="ita">이탈리아</option>
</select>
{input.country}
</div>
<div>
<textarea
onChange={onChangeBio}
value={input.bio}
placeholder="자기소개"
>
{input.bio}
</textarea>
{input.bio}
</div>
</div>
);
};
export default Register;
// 리팩토링 결과, ...input을 선언하여야지 다른 값도 값이
없다고 상태가 업데이트 됨**
아래와 같이 통합 이벤트 핸들러로 설정하여 적용할 수 있음
// 간단한 회원가입 폼
// 1. 이름
// 2. 생년월일
// 3. 국적
// 4. 자기소개
import { useState } from "react";
const Register = () => {
const [input, setInput] = useState({
name: "",
birth: "",
country: "",
bio: "",
});
const onChange = (e) => {
setInput({
...input,
[e.target.name]: e.target.value,
});
};
return (
<div>
<div>
<input
value={input.name}
onChange={onChange}
type="text"
placeholder="이름"
/>
</div>
<div>
<input value={input.birth} onChange={onChange} type="date" />
</div>
{input.birth}
<div onChange={onChange} value={input.country}>
<select>
{/* select 태그에 빈 태그를 추가하려면 바로 아래처럼 아무것도 입력하지 않으면 됩니다. */}
<option value=""></option>
{/* 이렇게 설정하게 되면 만약 한국을 선택할 때, 상태 값은 kr로 나오고 한국으로 나오지 않습니다. */}
<option value="kr">한국</option>
<option value="us">미국</option>
<option value="uk">영국</option>
<option value="gr">독일</option>
<option value="fr">프랑스</option>
<option value="ita">이탈리아</option>
</select>
{input.country}
</div>
<div>
<textarea
onChange={onChange}
value={input.bio}
placeholder="자기소개"
>
{input.bio}
</textarea>
{input.bio}
</div>
</div>
);
};
export default Register;
[useRef - 컴포넌트의 변수 생성하기]
import { useState, useRef } from "react";
const Register = () => {
const [input, setInput] = useState({
name: "",
birth: "",
country: "",
bio: "",
});
const countRef = useRef(0);
const inputRef = useRef(null);
const onSubmit = () => {
if (input.name === "") {
// 이름을 입력하는 DOM 요소에 포커스를 맞춤
inputRef.current.focus();
}
};
const onChange = (e) => {
countRef.current++;
console.log(countRef.current);
setInput({
...input,
[e.target.name]: e.target.value,
});
};
return (
<div>
<div>
<input
ref={inputRef}
value={input.name}
onChange={onChange}
name="name" // 이름을 입력하는 인풋의 name 속성 추가
type="text"
placeholder="이름"
/>
</div>
<div>
<input
value={input.birth}
onChange={onChange}
name="birth" // 생년월일 인풋의 name 속성 추가
type="date"
/>
</div>
<div>
<select
onChange={onChange}
value={input.country}
name="country" // select의 name 속성 추가
>
<option value=""></option>
<option value="kr">한국</option>
<option value="us">미국</option>
<option value="uk">영국</option>
<option value="gr">독일</option>
<option value="fr">프랑스</option>
<option value="ita">이탈리아</option>
</select>
</div>
<div>
<textarea
onChange={onChange}
value={input.bio}
name="bio" // textarea의 name 속성 추가
placeholder="자기소개"
></textarea>
</div>
<button onClick={onSubmit}>제출</button>
</div>
);
};
export default Register;
React Hooks : 클래스 컴포넌트의 기능을 함수 컴포넌트에서도 이용할 수 있도록 하는 메서드
class 컴포넌트 => 문법이 복잡함(사용 x)
{😎 리액트 훅은 이름 앞에 동일한 접두사 use가 붙음}
[3가지 hook 관련된 팁]
1. 반드시 함수 컴포넌트, 커스텀 훅 내부에서만 호출 가능
이렇게 컴포넌트 바깥에서 호출하게 되면 즉시 오류가 발생합니다.
2.조건부로 호출될 수는 없다. (조건문과 반복문 내부에서 훅을 호출할 수 는 없는 것을 의미)
3.커스텀 훅을 직접 만들 수 있다.
여기서 드래그한 부분들을 커스텀 훅을 작성하려고 하려면 드래그 한 내용을 복사하여 아래와 같이 getInput 을 만들어 사용하면 됩니다.
이때, 커스텀 훅을 만드는 방법은 함수의 이름 앞에 use를 붙여 만약에, getInput을 커스텀 훅으로 만들면 useInput 이렇게 작성하여 만들면 됩니다.
커스텀 훅을 사용할 때, 파일을 관리하는 방법 -> src 디렉터리 내부에 components와 동일하게 파일을 저장하지 않고 따로 hooks라는 파일로 훅의 이름으로 작성하는 것이 일반적
여기서는, useInput이 커스텀 훅이므로 hooks 디렉터리 내부에 useInput.jsx라는 파일로 생성하여 작성하는 것을 말함!
'프론트엔드(Web) > React' 카테고리의 다른 글
React 라이프 사이클 (feat. useEffect 함수 사용 방법) (2) | 2024.11.10 |
---|---|
React reducer,최적화, 페이지 라우팅 (1) | 2024.10.03 |
리액트 데이터 통신 - 데이터 통신, Suspense와 ErrorBoundary, tanstack query (3) | 2024.08.28 |
리액트 컨텍스트 - useContext, zustand (0) | 2024.08.28 |
리액트 메모이제이션- useCallback,useMemo,React.memo,useReducer (4) | 2024.08.27 |