리액트란?
리액트는 자바스크립트를 편하게사용할수있도록 만들어진 자바스크립트 라이브러리다.
굳이 리액트를 안쓰고도 js로 개발 가능하지만 규모가 커질수록 불편하기때문에 편하게 사용하기 위함.
여러개의 라이브러리가 존재.
- angular.js
- react.js
- vue.js
- backbone
리액트는 컴포넌트의 모음이다.
리액트는 바뀐뷰을 기존방식처럼 업데이트 해주지않고 바뀐뷰만 삭제하고 다시 만들어버린다.
성능적으로 문제가 있을것같지만 virtual DOM을 활용하여 바뀐부분만 찾아서 바꿔줌.
리액트는 컴포넌트로 여러가지 파일을 분리 저장.
일반 자바스크립트가 아닌 JSX라는 문법으로 작성.
(그냥 쉽게 자바스크립트안에서 html문법을 쓸수있게 지원해준게 JSX라고 생각하면 편함)
리액트 설치
리액트는 jQuery 같이 단순히 <script src="..."><script> 의 형태로 불러와서 사용했던것 처럼 사용하지는 않는다.
리액트를 제대로 사용하려면 Node, yarn, Webpack, Babel 등의 도구를 설치해야한다.
- Node.js: webpack과 babel을 사용하기 위하여 node.js설치
- yarn : 개선된 npm이라고 생각하면됨. 더 나은 속도, 더 나은 캐싱 시스템을 활용하기 위함.
- Webpack : 여러가지 파일을 한개로 결합하기위함
- Babel : 자바스크립트 문법들을 사용하기위함
설치
npm init react-app 프로젝트명 // react-app으로 필요한 모든것을 설치해줌
cd 프로젝트명
npm install react-router-dom@6 // 라우팅 기능 설치
npm start
메뉴를 클릭할때마다 원하는 컴포넌트를 매핑시켜서 보여주는걸 ‘라우팅’이라고함
리액트에서 라우팅 처리를 위해 모듈 설치를 추가적으로 해야함
설치되었다면 package.json에 "react-router-dom": "^6.21.3",가 추가됨.
ES6
자바스크립트가 사용하는 ECMAScript의 가장 최신 버전
리액트를 알기전에 반드시 ES6문법부터 익혀야 한다.
변수
- let : 가변변수로 재정의는 가능하지만 재선언은 불가.
- const : 불변변수로 재선언 재정의 모두 불가
var : 재정의와 재선언 모두가능 (이제는 안씀)
템플릿 리터럴
ES6부터 새로 도입된 문자열 표기법. 문자열 생성시 따옴표 대신, 백틱(`)을 사용.
따옴표와 달리 백틱 안에서는 줄바꿈이 반영됨. 문자열 사이에 변수나 연산을 넣을때는 ${}사이에 표현식 삽입.
var jsp = "자바스크립트";
// 기존 코드
console.log("이건 " + jsp + "입니다.");
// 템플릿 리터럴 방식
console.log(`이건 ${jsp}입니다.`);
// 출력 결과 -> 이건 자바스크립트입니다.
화살표함수
함수표현식을 보다 단순하고 간결하게 작성하는 문법
- 인수가 하나밖에 없다면 인수를 감싸는 괄호를 생략할 수 있다.
- 인수가 하나도 없을 땐 괄호를 비워놓으면 된다. 다만, 이 때 괄호는 생략할 수 없다.
- 본문이 한 줄 밖에 없다면 중괄호를 생략할 수 있다.
- 중괄호는 본문 여러 줄로 구성되어 있음을 알려주며, 중괄호를 사용했다면 return으로 결괏값을 반환해주어야 한다.
// 기본 함수 형식
let sum = function(a, b) {
return a + b;
};
// 화살표 함수 형식
let sum = (a, b) => a + b;
모듈 export/import
// named export 기본 형식
export { 모듈명1, 모듈명2 };
import { 모듈명1, 모듈명2 } from 'js 파일 경로';
// default export 기본 형식
export default 모듈명;
import 모듈명 from 'js 파일 경로';
클래스
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
nextYearAge() { // 메서드 생성
return Number(this.age) + 1;
}
}
// 클래스 상속
class introducePerson extends Person {
constructor(name, age, city, futureHope) {
// super 키워드를 이용해서 자식 class에서 부모 메서드를 호출
super(name, age, city);
this.futureHope = futureHope
}
introduce () {
return `저는 ${this.city}에 사는 ${this.name} 입니다.
내년엔 ${super.nextYearAge()}살이며,
장래희망은 ${this.futureHope} 입니다.`
}
}
let abc = new introducePerson('name','23','seoul', '개발자');
console.log(abc.introduce())
구조분해할당
객체와 배열의 값을 쉽게 변수로 저장할 수 있다.
const introduce = {name: 'unknown', age: 23};
// key와 같은 이름으로 변수 선언
const { name, age } = introduce;
// 다른 이름으로 변수 선언 -> 변수이름: 키값
const { myName: name, myAge: age } = introduce;
console.log(myName) // unknown
console.log(myAge) // 23
const fruits = ['apple', 'mango', 'grape'];
// 앞에서부터 순차적으로 변수 선언 가능
const [zero, one, two] = fruits;
console.log(zero) // apple
나머지 매개변수
나머지 후속 매개변수들을 묶어 하나의 배열에 저장해서 사용.
‘…’는 하나만 존재할수있고 반드시 마지막이여야한다.
// args에 1,2,3,4,5가 한꺼번에 배열로 담겨 인자로 넘겨진다.
function func1(...args) {
console.log(`args: [${args}]`)
// args: [1,2,3,4,5]
}
func1(1,2,3,4,5);
// arg1에는 1, arg2에는 2, arg3에는 나머지 3,4,5가 배열로 담겨 인자로 넘겨진다.
function func2(arg1, arg2, ...arg3) {
console.log(`arg1: ${arg1}, arg2: ${arg2}, arg3: [${arg3}]`)
// arg1: 1, arg2: 2, arg3: [3,4,5]
}
func2(1,2,3,4,5);
전개구문
묶인 배열 혹은 객체를 개별적인 요소로 분리한다. 나머지 매개변수의 반대라고 생각하면된다.
let arr = [1, 2, 3, 4, 5];
console.log(...arr);
// 1 2 3 4 5
var str = 'javascript';
console.log(...str);
// "j" "a" "v" "a" "s" "c" "r" "i" "p" "t"
forEach() / map()
forEach() : 배열 요소마다 한번씩 주어진 함수실행
배열.forEach((요소, 인덱스, 배열) => { return 요소 });
map() : 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열 반환
배열.map((요소, 인덱스, 배열) => { return 요소 });
리액트 사용
변수사용
const name ="tom" // 선언
const naver = {
name: "네이버",
url: "www.naver.com",
};
welcome, {name}. // 사용 - 숫자 & 문자열은 가능하나 bool & 객체는 표현불가능
welcome, {naver.name}. // 가능
컴포넌트사용
함수형 컴포넌트 / 클래스형 컴포넌트 2가지 방법이 있음.
클래스형 컴포넌트
import React from "react";
class Home extends Component {
render(){
return <h1>home 화면 입니다.</h1>
}
}
export default Home;
함수형 컴포넌트 (이걸 더 많이씀)
import React from "react";
function Home(){
return <h1>home 화면 입니다.</h1>
}
const About = () => {
return <h1>home 화면 입니다.</h1>
}
export default Home;
import Hello from './component/Hello';
...
<Hello /> // 이런식으로 사용하면됨
...
스타일적용
컴포넌트 단위로 관리되는게 편함.
1. 인라인 (거의 안씀) css는 객체로 넣어야함.
<div>
<p style={
{
color: 'red',
borderRight: '2px solid black',
}
} >Hellooooooo</p>
</div>
2. css 파일 따로 분리
index.css 전체 프로젝트에 영향
App.css App컴포넌트의 한정된 영향인줄알았지만, 헤더를 통해서 다 연결되어있음
그래서 각컴포넌트에 특화된 css모듈을 작성해야함.
Hello.module.css 만들고
.box {
width: 200px;
height: 50px;
background-color:blue;
}
그리고 사용하는부분에서
import styles from "./Hello.module.css";
<div className={styles.box}> 이렇게 {}로 감싼다
이벤트적용
2가지 방법 존재.
1. 미리 만들어서 사용
function showName() {
console.log("abc");
}
<button onClick={showName}>show name</button>
2. 선언과 동시에 만듬
<button onClick={() => {
console.log(30);
}} >show age</button>
function showText(e) {
console.log(e.target.value); // e(이벤트)의 타겟(input)의 값을 찍으라는뜻
}
<input type="text" onChange={showText} />
state
컴포넌트가 가지고 있는 상태값. 이 상태값이 변하면 리액트는 자동으로 ui를 업데이트함
초기 리액트 : 클래스형 컴포넌트 (state, lifestyle) / ui표현만 함수형 컴포넌트로 사용
16이후 : 모든 컴포넌트를 함수형 컴포넌트로 만들수있게됨.
동일 컴포넌트라도 각 state는 다른 state에 영향을 미치지 않는다.
state로 관리하겠다고 명시했으면 set..이런걸로해줘야함
num = num + 1로는 변경이 안됨.
import { useState } from "react";
const Hello = function () {
const [name, setName] = useState("mike"); // 인수는 초기값
function changeName(){
const newName = name === "mike" ? "jane" : "mike";
setName(newName);
}
<h2>{name}</h2>
props
props는 부모로부터 넘겨받은값. 변경불가능.
변경하고싶다면 내부에서 state로 만들어줘야함.
부모
<Hello age={10}/>
자식
const Hello = function (props) {
...
<h2>{props.age}</h2>
}
age = props.age 를
{age} = props 로 쓸 수 있습니다.
function(props){
console.log(props.age);
console.log(props.name);
}
function({age, name}){
console.log(age);
console.log(name);
}
map반복문
배열을 받아서 또다른 배열을 만들어줌
dummy.days.map(abc => (
<li key={day.id}>Day {abc.day}</li>
))
const a = [1,2,3,4,5];
const b = a.map(number => number * 2);
dom
dom 라이브러리를 받아서 활용.
import {BrowserRouter, Route, Routes } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<div className="App">
<Header />
<Routes>
<Route exact path="/" element={<DayList />} /> // 컴포넌트끼리 영향x
<Route path="/day/:day" element={<Day />} />
<Route element={<EmptyPage />} />
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
useEffect
어떤 상태값이 바뀌었을때 다시 랜더링 되었을때 호출
count상태값이 바뀌었을때 useEffect가 알아서 호출됨.
근데 어떤값이 바뀌어도 호출되기때문에 불필요하게 호출되는것을 방지하기위해서 2번째 매개변수활용. 최초 한번만 호출하려면 빈배열입력.
import { useState, useEffect } from "react";
..
const [count, setCount] = useState(0);
onclick(){
setCount(count + 1);
}
//useEffect(() => {
// console.log("change");
// }
//)
useEffect(() => {
console.log("change");
}, [count] // count상태값이 변했을때만 실행
);
useEffect(() => {
console.log("change");
}, [] // count상태값이 변했을때 단 한번 실행
);
<button onClick={onclick}>{count}</button>
커스텀hook
useEffect, useState같이 리액트가 제공해주는 hook도 있지만 직접 커스텀hook을 만들수도있다.
이런식으로 fetch내용만 다르고 나머지는 비슷하다면 커스텀hook을 만들어서 사용하는것이 좋다.
const [words, setWords] = useState([]);
useEffect(() => {
fetch(`http://localhost:3001/words?day=${day}`)
.then(res => {
return res.json();
}).then(data => {
setWords(data);
});
}, [day]);
import { useState, useEffect } from "react";
export default function useFetch(url){
const[data, setData] = useState([]);
useEffect(() => {
fetch(url)
.then(res => {
return res.json();
}).then(data => {
setData(data);
});
}, [url]);
return data;
}
사용하는쪽에서 useFetch()를 사용하면됨.
배열 반복
import React from 'react';
const User = ({userData}) => {
return (
<tr>
<td>{userData.name}</td>
<td>{userData.email}</td>
</tr>
)
}
const UserList = () => {
const Users = [
{email: 'ryu@naver.com', name: '유재석'},
{email: 'kim@naver.com', name: '김종국'},
{email: 'ha@naver.com', name: '하하'},
{email: 'song@naver.com', name: '송지효'},
];
return (
<table>
<thead>
<tr>
<th>이름</th>
<th>이메일</th>
</tr>
</thead>
<tbody>
{Users.map(user =>
<User userData={user} />
)}
</tbody>
</table>
)
}
export default UserList;
참고
'IT > ETC' 카테고리의 다른 글
REST API (0) | 2023.03.26 |
---|---|
JSP vs 서블릿 (0) | 2023.03.26 |
HTTP 상태코드 (0) | 2023.03.26 |
POSTMAN을 통한 웹 테스트 자동화 만들기 (0) | 2023.03.26 |
GIT 설치 및 사용법 (0) | 2022.01.24 |
댓글