ㅇㅇㅈ Blog

프론트엔드 수행중

0%

Rerender

JavaScript 와 React 의 차이

1
2
3
4
5
6
7
8
9
10
11
//vanilla
function random() {
const number = Math.floor(Math.random() * (10 - 1) + 1);
const element = `
<button>${number}</button>
`;
document.querySelector("#root").innerHTML = element;
}
random();

setInterval(random, 1000);

바닐라JS 에서는 element가 변경될때 element를 다시 그림

1
2
3
4
5
6
7
8
9
//react
function random() {
const number = Math.floor(Math.random() * (10 - 1) + 1);
const element = <button>{number}</button>
ReactDOM.render(element, root)
}
random();

setInterval(random, 1000);

React에서는 변경되는 부분만 다시 그린다

렌더링 된 엘리먼트 업데이트하기

두 개의 트리를 비교할 때, React는 두 엘리먼트의 루트(root) 엘리먼트부터 비교합니다. 이후의 동작은 루트 엘리먼트의 타입에 따라 달라진다.

엘리먼트의 타입이 다른 경우

두 루트 엘리먼트의 타입이 다르면, React는 이전 트리를 버리고 완전히 새로운 트리를 구축한다
<a>에서 <img>로, <Article>에서 <Comment>로, 혹은 <Button>에서 <div>로 바뀌는 것 모두 트리 전체를 재구축하는 경우

DOM엘리먼트의 타입이 같은 경우

같은 타입의 두 React DOM 엘리먼트를 비교할 때, React는 두 엘리먼트의 속성을 확인하여, 동일한 내역은 유지하고 변경된 속성들만 갱신한다

1
2
3
<div className="before" title="stuff" />

<div className="after" title="stuff" />

이 두 엘리먼트를 비교하면, React는 현재 DOM 노드 상에 className만 수정한다

for..in

for in 반복문은 객체에서 주로 사용

  • 객체 자료형에서 ‘열거’ 할 수 있는 자료들을 순회할 수 있도록 해준다
  • 특정 순서에 따라 인덱스를 반환하는 것을 보장 할 수 없다 (반복되는 순서가 구현에 따라 다르다)
  • 배열 데이터에서는 인덱스값이 중요하므로 forEach나 for..of를 권장한다
1
2
3
4
5
6
7
8
9
10
11
12
13
for (variable in object) { ... }

// 예제
const object = { a: 1, b: 2, c: 3 };

for (const property in object) {
console.log(`${property}: ${object[property]}`);
}

// expected output:
// "a: 1"
// "b: 2"
// "c: 3"

variable : 매번 반복마다 객체의 키 값이 variable로 지정된다

object : 반복 작업을 수행할 객체 (열거형 속성을 가지고 있는객체 )

객체 데이터는 만들때 개발자가 적은 키:밸류 값만 저장되는게 아닌 그 외 숨겨진 속성 3개가 같이 저장된다

1
2
3
4
5
6
7
8
9
10
11
숨겨진 속성을 확인해보는 메서드 Object.getOwnPropertyDescriptor()

let book = {
title: "자바스크립트 완벽하게 이해하기",
price: 32000,
author: "훈이",
publisher: "자바스크립트짱짱",
};

// Obejct.getOwnPropertyDescriptor(객체명,'객체키명')
console.log(Object.getOwnPropertyDescriptor(book, "title"));

숨겨진 속성들을 이용해 객체데이터의 값을 열거불가,수정불가,삭제불가 등을 할 수있음..

writable 이 false 이면 변경불가 → default : true

enumerable 이 false 이면 열거 불가 → default : true

configurable 이 false 이면 enumerable 및 configurable을 변경 불가 및 삭제 불가 하지만 쓰기 writable은 가능 → default : true

[JavaScript]객체 속성(writable, enumerable, configurable)

React-router-dom v6

강의에서는 5버전으로 강의해서 그냥 따라하다가 안돼서 v6으로 버전업해서 진행..

Routes

5버전에 있던 Switch가 Routes로 변경되었다
그리고 Route를 Routes로 감싸주지 않으면 에러가 발생한다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { Routes, Route } from 'react-router-dom'
import './App.css'

import Home from './pages/Home'
import Profile from './pages/Profile'
import About from './pages/About'
import NotFound from './pages/NotFound'
import Links from './components/Links'
import NavLinks from './components/NavLinks'
import Login from './pages/Login'

function App() {
return (
<>
<Links></Links>
<NavLinks></NavLinks>
<Routes>
<Route path='/login' element={<Login></Login>}></Route>
<Route path='/profile/:id' element={<Profile />}></Route>
<Route path='/profile' element={<Profile />}></Route>
<Route path='/about' element={<About />}></Route>
<Route path='/' element={<Home />}></Route>
{/* Not Found */}
<Route path='/*' element={<NotFound />}></Route>
</Routes>
</>
)
}
export default App
  • Route 에서 변경점
    • 5에서는 component = { Home } 방식으로 연결했다면
    • 6에서는 element = {<Home />} 처럼 컴포넌트를 연결 해줘야 한다
  • exact를 통해 복수 라우팅을 방지했는데 exact가 삭제됨
    • 여러 라우팅을 매칭하기 위해 ‘*’ 을 붙인다
1
<Route path='/*' element={<NotFound />}></Route>

URL 파라미터와 쿼리

  • 파라미터 : ‘profile/1’
  • 쿼리 : ‘about?name=mark’

URL 파라미터 useParams

6버전에서는
useParams로 파라미터를 조회한다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { useParams } from 'react-router-dom'
function Profile() {
const parmas = useParams()
console.log(params)
return (
<div>
<h2>Profile 페이지 입니다.</h2>

{parmas.id && <p>id 는 {parmas.id} 입니다</p>}
</div>
)
}
export default Profile

console로 찍어보면 객체데이터로 출력된다

URL 쿼리

useLocation을 사용해 조회한다

URL 쿼리는 “?name=mark”과 같이 문자열로 되어 있고, 특정 값을 읽어 오기 위해서는 문자열을 객체 형태로 반환해야한다. 그 과정에서 qs 라는 라이브러리를 사용한다.

1
2
3
4
5
6
7
8
9
10
11
12
import queryString from 'query-string'
import { useLocation } from 'react-router-dom'

export default function About() {
const search = useLocation()
console.log(search)
return (
<div>
<h2>About</h2>
</div>
)
}

search를 콘솔로 찍어보면 여러 속성이 들어있다



현재 프로젝트에서는 search 부분만 필요하므로 search만 구조분해로 받아온다

1
2
3
4
5
6
7
8
9
10
11
12
import queryString from 'query-string'
import { useLocation } from 'react-router-dom'

export default function About() {
const { search } = useLocation()
console.log(search)
return (
<div>
<h2>About</h2>
</div>
)
}

문자열로 찍힌다
qs로 격체 형태로 변환해서 사용 하면 된다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import queryString from 'query-string'
import { useLocation } from 'react-router-dom'

export default function About() {
const { search } = useLocation()
console.log(search)
const query = queryString.parse(search)
return (
<div>
<h2>About</h2>
{query.name && <p>name은 {query.name}입니다.</p>}
</div>
)
}

useNavigate

useNavigate를 통해 사용자를 특정 Url로 리디렉션 한다

1
2
3
4
5
6
7
8
9
10
import { useNavigate } from 'react-router-dom'
export default function LoginButton() {
const navigate = useNavigate()
function login() {
setTimeout(() => {
navigate('/')
}, 1000)
}
return <button onClick={login}>로그인하기</button>
}

수박수박수

문제

길이가 n이고, “수박수박수박수….”와 같은 패턴을 유지하는 문자열을 리턴하는 함수, solution을 완성하세요.
예를들어 n이 4이면 “수박수박”을 리턴하고 3이라면 “수박수”를 리턴하면 됩니다.

제한 조건

  • n은 길이 10,000이하인 자연수

입출력 예

n return
3 “수박수”
4 “수박수박”

soulution

  1. 인자로 받은 n 만큼 for문을 돈다
  2. i를 2로 나누었을때 몫이 0일 경우에 수를 추가해준다 아니면 박을 추가해준다
1
2
3
4
5
6
7
8
9
function solution(n) {
var answer = ''
for (let i = 0; i < n; i++) {
i % 2 === 0 ? (answer += '수') : (answer += '박')
}
console.log(answer)
return answer
}
solution(3)

다른 사람 풀이

1
2
3
4
const waterMelon = n => "수박".repeat(n).slice(0,n);

console.log("n이 3인 경우: "+ waterMelon(3))
console.log("n이 4인 경우: "+ waterMelon(4))

repeat()과 slice() 사용했다

repeat()은 문자열을 주어진 횟수만큼 반복 해준다

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String/repeat

1
'수박'.repeat(3) // "수박수박수박" 이 된다

이후 slice()로 0번째서 시작해 인자로 받은 n개만큼(n번째 인덱스의 그 바로 전까지만 추출된다) 추출 해준다…

Switch

  • 여러 route 중 순서대로 먼저 맞는 하나만 보여준다
  • exact를 뺄 수 있는 로직을 만들 수 있다
  • 가장 마지막에 어디 path에도 맞지 않으면 보여지는 컴포넌트를 설정해서, “Not Found”페이지를 만들 수 있다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import './App.css'
import Home from './pages/Home'
import Profile from './pages/Profile'
import About from './pages/About'
import NotFound from './pages/NotFound'

function App() {
return (
<BrowserRouter>
<Switch>
<Route path='/profile/:id' component={Profile}></Route>
<Route path='/profile' component={Profile}></Route>
<Route path='/about' component={About}></Route>
<Route path='/' exact component={Home}></Route>
{/* Not Found */}
<Route component={NotFound}></Route>
</Switch>
</BrowserRouter>
)
}
export default App
  • Path의 순서를 조정해준다

    • 루트경로인 ‘/‘은 모든 경로에 포함되어 있기 때문이다
    • 루트경로인 ‘/‘은 exact 여야 한다
    • profile과 profile/:id 는 porfile이 겹치는 범주이기 때문에 exact를 쓰지 않고 표현할려면 순서를 조정해야 한다
  • NotFound 페이지는 path를 지정하지 않고 컴포넌트를 지정해준다

1
2
3
export default function NotFound() {
return <div> 페이지를 찾을 수 없습니다 </div>
}


없는 주소일 경우 notfound 컴포넌트를 출력한다

React-router-dom v5

  1. 브라우저에서 최초에 root 경로로 요청을하면,
  2. React Web App을 내려준다
  3. 내려받은 App 에서 다른 페이지로 이동하는 동작을 수행하면,
  4. 새로운 경로에 맞는 컴포넌트를 보여준다
1
$ npm i react-router-dom
  • cra에 기본 내장된 패키지가 아님
  • react-router-dom은 facebook의 공식 패키지가 아니다

특정 경로에서 보여줄 컴포넌트 준비

  • ‘/‘ => Home 컴포넌트
  • ‘/profile’ => Profile 컴포넌트
  • ‘/about’ => About 컴포넌트
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { BrowserRouter, Route } from 'react-router-dom'
import './App.css'
import Home from './pages/Home'
import Profile from './pages/Profile'
import About from './pages/About'

function App() {
return (
<BrowserRouter>
<Route path='/' component={Home}></Route>
<Route path='/profile' component={Profile}></Route>
<Route path='/about' component={About}></Route>
</BrowserRouter>
)
}

export default App
Read more »

Object.is()

Object.is()는 인자로 받는 두 값이 같은지 확인해서 boolean으로 반환한다

구문

1
2
3
Object.is(value1, value2)

// true or false

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Object.is('foo', 'foo');     // true
Object.is(window, window); // true

Object.is('foo', 'bar'); // false
Object.is([], []); // false

var test = { a: 1 };
Object.is(test, test); // true

Object.is(null, null); // true

// 특별한 경우
Object.is(0, -0); // false
Object.is(-0, -0); // true
Object.is(NaN, 0/0); // true

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/is

Getting Started with Create React App

1
$ npx create-react-app [Project]

npx 이용해 그냥 설치시 아래 에러 코드가 뜨면서 설치가 되지 않는다

@latest를 붙여서 설치해주면 된다

1
2
3
4
5
6
7
You are running `create-react-app` 4.0.3, which is behind the latest release (5.0.1).

We no longer support global installation of Create React App.

Please remove any global installs with one of the following commands:
- npm uninstall -g create-react-app
- yarn global remove create-react-appcd
1
$ npx create-react-app@latest [Project]

ESlint

일반적인 프로젝트에서

ESlint 라이브러리 설치

1
$ npm i eslint -D

ESlint 초기화
.eslintrc.js 파일이 생성된다

1
$ npx eslint --init

.eslintrc.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 다양한 옵션들 설정 가능
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: 'eslint:recommended',
parserOptions: {
ecmaVersion: 'latest',
},
rules: { // 룰을 추가해 줄 수있다
semi: ['error', 'always'],
},
}
Read more »

Object.entries()

Object.entries()는 객체 자체의 열거 가능한 문자열 키를 가진 속성 [key, value] 쌍이 반환되는 객체이다.

key는 문자열이 된다

1
2
3
4
5
6
7
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj));
// [ ['foo', 'bar'], ['baz', 42] ]

const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj));
// [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]

Array.reduce()

배열의 각 요소에 대해 주어진 리듀서(reducer)함수를 실행하고, 하나의 결과값을 반환한다

말이 어렵다..

1
arr.reduce(callback[, initialValue])

reduce()의 콜백 함수는 4가지 인수를 받는다

1
2
3
4
5
6
7
8
1. accumulator
- 누산기, 콜백의 반환값을 누적시킨다. initialValue를 제공했을때는 initialValue의 값이다
2. currentValue
- 처리할 현재 요소
3. currentIndex (optional)
- 처리할 현재 요소의 인덱스
4. array (optional)
- reduce()를 호출한 배열

사용 방법

reduce()에는 누산기가 포함되어 있기 때문에, 배열의 각 요소에 대해 함수를 실행하고 누적된 값을 출력할때 용이하다.

1
2
3
4
5
const numbers = [1,2,3,4,5]
const result = numbers.reduce((acc, cur, idx)=>{
return acc + cur
},0)
console.log(result) // 15

예제에서 initialValue 를 0 으로 주었기 때문에 초기값이 0부터 시작해서 하나씩 누적 시켜 나간다
0+1+2+3+4+5 = 15

1
2
3
4
5
const numbers = [1,2,3,4,5]
const result = numbers.reduce((acc, cur, idx)=>{
return acc + cur
},10)
console.log(result) // 25

initialValue 를 10 으로 주었기 때문에 초기값이 10부터 시작해서 하나씩 누적 시켜 나간다
10+1+2+3+4+5 = 15

reduce()로 많은 것을 할 수 있다는데.. 아직 더해서 누적 시키는 정도 밖에 이해가 되질 않는다