View

Object

정적메소드(static method)

Object.assign()과 같이 prototype이 없는 경우(Object.prototype.assign이 아님)

{}.assign()과 같이 사용할 수 없음.

 

Object.assign()

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

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

source에서 속성이 target으로 복사되어 들어간다.

target또한 변경되고 returnedTarget에도 같은 output이 표시된다.

console.log(target === returnedTarget); // true 출력

 

브라우저 콘솔을 이용하여 확인해 본 결과

생김새가 같다고 하여 true 가 반환되는 것이 아니다.

객체 데이터는 메모리 주소를 참조하고 있고(참조형 데이터 : 객체 데이터, 배열 데이터, 함수), 같은 메모리 주소를 가리키고 있어야 === 으로 비교하였을 때  true값이 반환된다.

원시형 데이터는 값이 같으면, true라고 나올 수 있으나 참조형 데이터는 그렇지 않다.

 

객체를 합쳐서 새로운 객체 데이터로 만들경우

const returnedTarget2 = Object.assign({}, target, source);

위와 같이 할 경우에는 target에는 변화 없이 returnedTarget2에만 변경된 데이터가 들어간다.(원본의 데이터는 손상없이 객체 데이터를 합친 새로운 객체 데이터를 만들 수 있다.)

 

이를 이용하여 객체 데이터의 복사본을 만들 수 있다.

const copyTarget = Object.assign({}, target);

returnedTarget2, copyTarget은 === 비교 연산자로 target과 비교하였을때 false가 반환된다.

copyTarget이 비록 target과 형태는 같더라도 다른 메모리 주소에 위치하게 되는 것이다.

 

객체데이터도 배열 데이터처럼 인덱싱방법으로 데이터를 꺼내올 수 있다.

const arr = [1, 2, 3];
arr[0]; // 1
const obj = {a: 1};
obj["a"]; // 1

 

구조 분해 할당

해당 key값이 undefined일 경우 기본 값 지정

const {address = "Korea, Republic of"} = data;

data.adress에 값이 존재하는 경우 해당 값이 address 라는 변수에 저장되고, 존재하지 않는 경우에는 "Korea, Republic of"라는 string이 저장된다.

 

구조분해 할당으로 꺼내온 속성 이름을 변경

const {address: myAddress} = data;

myAddress라는 이름의 변수에 저장된다.

 

배열의 경우에는 인덱스 순서대로 꺼내오면 된다.

const [name, address] = ["Kate", "Korea"];

위의 경우 address 부분(1번째 요소)만 추출하고 싶다면

const [, address] = ["Kate", "Korea"];

와 같이 , 로 구분하여 작성한다.(0번째가 아닌 몇번째 인덱스이든, 같다.)

 

데이터 불변성 Immutability

원시데이터 

자바스크립트에서 사용할 수 있는 기본 데이터

String, Number, Boolean, undefined, null

참조형 데이터

Object, Array, Function

함수의 인수로 사용되는 콜백함수도 데이터로 사용될 수 있기때문에 Function 포함

 

비교 연산자(===)로 비교 시에 같다고 나오는 것은,

서로 바라보고 있는 메모리 주소가 같은 것이다. 저장되는 값이 같기 때문이 아니다.

원시데이터는 값이 같으면 같은 메모리 주소를 가지고 있겠지만, 참조 데이터의 경우에는 다르다.

 

원시데이터가 기존 메모리주소에 존재한다면, 기존에 존재하는 메모리 주소를 바라보도록한다.

원시데이터는 한 번 만들어지면 불변한다. -> 데이터 불변성

 

참조형 데이터는 생김새가 같더라도 같은 데이터가 아닐 수 있다.(메모리 주소가 다르다!)

새로운 값을 만들 때마다 새로운 메모리 주소에 할당된다.

참조형 데이터는 불변성이 없다. 가변한다.

같은 메모리 주소를 바라보는 경우, 해당 메모리 주소의 데이터를 변경하였을 때 의도치 않게 다른 데이터까지 변경될 수 있다.

a, b는 같은 메모리 주소를 가리키고 있으므로

a.a의 값만 1에서 2로 변경하여도 b.a 또한 2라는 값을 가지게 된다.

 

b에는 새로운 객체가 복사되어 저장되는 것이 아니고, 메모리의 참조 주소만 저장된다. (할당 연산자 = 사용시)

 

할당연산자를 사용시 복잡한 데이터를 다룰 때 문제가 될 수 있으므로, 반드시 유의해 두어야 한다.

완전히 다른 데이터로 구분해서 사용하고 싶다면 복사(얕은 복사, 깊은 복사)하여야 한다.

const user = {
  name: "Kate",
  age: 20,
  emailAddresses: ["abcd@efg.com"]
}

const copyUser = user;
console.log(user === copyUser); // true

user.age = 30;
console.log(copyUser.age); // 30

user 의 데이터를 수정해도, copyUser또한 값이 함께 바뀌게 된다.(데이터에 의도하지 않은 변화가 일어날 수 있다.)

 

얕은 복사(Shallow copy)

const copyUser = Object.assign({}, user);
console.log(user === copyUser); // false

user.age = 30;
console.log(copyUser.age); // 20

Object.assign을 이용하여 복사

Object.assign(대상객체, 출처객체);

 

const copyUser = {...user};
console.log(user === copyUser); // false

user.age = 30;
console.log(copyUser.age); // 20

전개 연산자(...)를 사용하여 복사

 

깊은 복사(Deep copy)

위의 얕은 복사는 모두 아래와 같은 결과가 된다.

user.emailAddresses.push("a@abc.com");
console.log(user.emailAddresses === copyUser.emailAddresses); // true

user.emailAddresses 를 복사하지 않았으므로 user데이터 내부의 새로운 참조데이터 emailAddresses는 같은 주소를 공유하고 있으므로 true가 도출된다.

 

user 데이터 내부의 데이터는 복사되지 않음.

그 데이터 내부로 들어가 모든 데이터를 복사해야 한다. -> 깊은 복사

 

lodash의 깊은 복사

자바스크립트에서 구현하기 복잡하여, lodash를 이용해보자.

 

재귀 개념을 사용한 cloneDeep()사용

https://lodash.com/docs/4.17.15#cloneDeep

import _ from "lodash";

// 중략

const copyUser = _.cloneDeep(user); // 깊은 복사

https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L11087

 

✔ 참조형데이터 내부에 또 다른 참조형 데이터가 들어 있는 경우에는 깊은 복사를 하자!

 

import, export 

import _ from "lodash" // "node_modules"하위에서 "lodash"를 찾는다.
import func1 from "./function" // 상대경로 function.js에서 export default
import { func2 } from "./function" // export

default export 이름을 지정하지 않아도 된다.

named export 이름을 지정하여 내보내야 한다.

 

export default 

무기명으로 내보낼 수 있다. (export default function [여기에 이름이 없음]() { // 함수 내용 });

불러올때도 이름을 바꿀 수 있다 (import 원하는 이름 from 경로)

 

export

이름이 필요하다

가져올 때 {}를 사용하여야 한다. import { 이름 } from 경로

구조분해할당처럼 이름을 바꿀 수 있으나 :를 사용하지 않고 as를 사용한다.(import { func as random } from 경로)

 

export default 는 한 파일에서 하나만 내보낼 수 있다.

export 는 이름만 지정되어 있다면 몇 개를 내보내도 문제가 없다.

 

named export로 내보낸 모듈들은 와일드 카드(*)를 사용해서 모두 가져올 수 있다.

import * as N from "./fileName"

[N.내부의 모듈]과 같이 사용할 수 있다.

 

export와 export default를 한 파일 안에서 함께 사용할 수도 있다.

 

lodash

documentation: https://lodash.com/docs/4.17.15

 

배열 데이터가 하나일 때

배열 내에서 유일한 요소만 만들기 uniq

배열 내에서 유일한 요소를 특정 기준으로 만들기 uniqBy (예 : concat으로 연결 후, uniq혹은 uniqBy를 사용)

 

배열데이터가 여러개일 때

여러 배열을 유니크한 기준으로 합치기 unionBy 

 

find

배열에서 어떠한 조건에 해당하는 특정 객체 데이터 찾기 -> 데이터를 반환

_.find(배열, 조건);

 

findIndex 

_.findIndex(배열, 조건) -> 해당 데이터 객체의 인덱스를 반환

 

remove

_.remove(배열, 객체 데이터) 

해당 객체 데이터를 배열에서 제거한다.

 

JSON(JavaScript Object Notation)

자바스크립의 데이터를 표현하는 하나의 포맷

객체 데이터와 유사(key 속성 - value 값 쌍), 경량화 데이터(string) - 다시 객체 형태로 바꾸려면 JSON.parse

대표적으로 서버와의 통신에서 데이터를 주고 받을 때 많이 사용함.

문자열은 ""(큰 따옴표)로만 작성하여야 한다.

 

객체데이터는 속성(key)에 특수문자가 존재하는 경우 등에만 키를 따옴표로 감싸줘야 하고, 일반적인 경우에는 감싸줄 필요가 없다.

JSON문법에서는 속성이름을 큰 따옴표로 묶어야 한다.

 

json파일 하나가 하나의 데이터가 된다.

{
	"name"  : "Kate"
}

 

객체 데이터를 가진 json파일이 된다.

"Hi"
123

위와 같이 여러 데이터를 입력할 수 없다. 

 

undefined는 사용할 수 없다. (string, number, boolean, null, object, array 사용 가능)

 

import data from "./datafile.json"

이 경우 파일 확장자는 생략할 수 없는데, 파일 확장자를 생략할 수 있는 경우는 어디까지나 js 파일일 때이다.

 

json이라는 파일은 하나의 문자 데이터이다.

객체 데이터처럼 출력은 되지만(console.log사용시), 문자데이터이다.

객체데이터 처럼 사용가능(JSON.parse를 통하여 다시 객체 형태로 변경, 반대는 JSON.stringify ) 

 

Storage

Local Storage, Session Storage

mdn:
https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage


로컬스토리지는 도메인단위로 저장, 만료되지 않는다(반영구적).

세션 스토리지는 페이지 세션이 끝날 때 데이터가 사라진다.

 

localStorage.setItem(key, value);

문자데이터로 value 저장하는 것이 좋다(JSON.strigify)

Object를 그대로 value에 setItem 해주면, [Object Object]로 표시된다.

 

데이터 읽어오기

localStorage.getItem("item");

item이라는 이름의 key에 해당하는 값을 가져온다.

JSON.parse()를 이용하여 원래의 JavaScript 데이터로 변환

 

데이터 제거하기

localStorage.removeItem("item");

item이라는 key에 해당하는 데이터를 삭제한다.

 

데이터 수정하기

const stringData = localStorage.getItem("item");
const objData = JSON.parse(stringData);
objData.num = 22;

localStorage.setItem("item", JSON.stringify(objData));

원래 key이름으로 덮어씌워 주면된다.

 

lodash를 이용하여 localStorage 관리 - lowdb 패키지

lowdb : https://github.com/typicode/lowdb

브라우저의 데이터를 DB처럼 사용할 수 있다.

 

OMDb API

링크: https://www.omdbapi.com/

API Key 발급 하기: https://www.omdbapi.com/apikey.aspx

 

Query String (파라미터 라고도 함)

Query 검색

문자를 가지고 검색한다.

주소?속성=값&속성=값 과 같이 작성한다.

?로 시작하는 접속 옵션

 

API문서의 Usage를 따라 실습

https://www.omdbapi.com/?apikey=[Key]&s=frozen

위와 같은 형태로 요청할 수 있다.

 

Axios

promise기반 HTTP client (HTTP요청 처리), 브라우저, node.js에서 모두 동작

URL : https://github.com/axios/axios

 

브라우저에서 실제 HTTP 요청을 처리할 수 있어야 하므로 일반의존성으로 설치(dev dependency x)

npm install axios

 

import axios from "axios";

const fetchMovieData = () => {
	axios
    	.get("https://www.omdbapi.com/?apikey=[APIKey]&s=frozen")
    	.then(res => console.log(res));
}

fetchMovieData();

메소드 체이닝으로 작성

 

import axios from "axios";

const fetchMovieData = () => {
	axios
    	.get("https://www.omdbapi.com/?apikey=[APIKey]&s=frozen")
    	.then(res => {
        	const $h1 = document.querySelector("h1");
            const $img = document.querySelector("img");
            
            $h1.textContent = res.data.Search[0].Title;
            $img.src = res.data.Search[0].Poster;
        });
}

fetchMovieData();

응답으로 받아온 데이터중 0번째를 화면에 그려보기

 


React

React가 Vue, Angular, Svelte등 프레임워크 중 우위

 

라이브러리 : 공구. 개발편의를 위한 도구의 모음

프레임워크 : 공장과 같이, 기반 구조까지 잡혀있다.

리액트는 라이브러리의 성격을 가지고 있다(자유도가 높다. 다양하게 접목하여 사용)

 

 

Wappalyzer를 사용하여 어떤 기술을 사용하는지 확인할 수 있다.

tistory의 기술들

리액트의 장점

Virtual DOM, JSX, Flux, Functional Programming... 등

 

리액트를 풍성하게 해주는 라이브러리들이많고, 계속 나오고 있다. (swr, framer motion 등)

 

기술의 트렌드는 빠르게 변한다.

FE라는 분야의 인기있게 된 지는 오래되지는 않았다. 

따라서, 새로운 기술을 빠르게 익히는 능력이 중요하다.

리액트를 라이브러리로서 접근하고 공식문서를 토대로 반복하여 학습하기! 

새로운 기술을 익히는 요령과 패턴을 찾자.

다양한 라이브러리를 접해보자(리액트와 함께 사용하는)

 

DOM

Document Object Model

 

CDN

Content Delivery Network

웹에서 사용되는 다양한 컨텐츠를 저장하여 제공한다.

리액트 CDN Link:https://ko.reactjs.org/docs/cdn-links.html

const $root = document.getElementById("root");
const $h1 = React.createElement("h1", {
	children: "Hello, World!"
});

ReactDOM.render($h1, $root);

CDN링크를 삽입하여 위와 같은 React 문법을 사용할 수 있다.

vanilla JS에서는 document.createElement로 요소를 생성하고, appendChild

 

React.createElement로 만든 요소를 console로 확인해 보면, 

React가 생성한 어떤 객체 Symbol(react.element)을 만들고, props에 어떤 것이 들어있는 것을 확인할 수 있다.

 

React v 18 부터는 ReactDOM.render()대신 createRoot을 사용해야 한다.

https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#updates-to-client-rendering-apis

 

const $h1 = React.createElement("h1", null, "hello");
const $root = ReactDOM.createRoot(document.getElementById("root"));
$root.render($h1);

JSX문법

React.createElement 표현식

 

Babel이 JavaScript 문법으로 변경해준다.

Babel Link: https://babeljs.io/

Try It 에서 확인해 본 변환 결과

 

const text = "Hello World";
const $title = <h1 className="title">{text}</h1>;

babel의 변환 결과

"use strict";

const text = "Hello World";
const $title = /*#__PURE__*/React.createElement("h1", {
  className: "title"
}, text);

JSX spread연산자

const text = "Hello, World!";
const titleClassName = "title";
const props = {
	className: titleClassName,
	children: text
}

const myTitle = <h1 {...props}/>;
const myTitle = <h1 className={props.className} children={props.children}/>

위와 같은 표현을 spread 연산자로 표현할 수 있다.

 

JSX와 JS를 섞어서 사용할 수 있다. -> 이를 Interpolation 이라고 한다.

 

Vanilla JS : 변경이 생기면, Element를 다시 그린다

React: 변경된 부분만 다시 그린다.

- reflow, repaint에서 이점을 가질 수 있다.

 

React 엘리먼트는 불변객체(immutable)

변경하는지 판단은 React가 알아서 한다.(https://ko.reactjs.org/docs/rendering-elements.html)

변경되는지 어떻게 알 것인가? (https://ko.reactjs.org/docs/reconciliation.html)
Key, Prop 비교, virtual dom

 

vanilla JS: onclick, onmouseout...

React: camel case(onClick ...)

 

https://ko.reactjs.org/docs/rendering-elements.html

DOM: 논리 트리

Component : Element의 집합

Element: 요소

 

컴포넌트 사이드이펙트 다루기

React.useState(초기값)

초기값위치에 해당 초기값을 return하는 함수를 넣어줄 수 있다.

처음 값을 읽어오는 시간이 길더라도 Lazy Initialization가능

 

React.useEffect(()=> {

  // 어떤 동작

}, []);

두 번째 인자로 전달된 배열 - dependency Array 내의 keyword가 변경될때마다 동작한다.

바뀌면(주동작), 동작하라(사이드이펙트)

빈배열로 하면, 컴포넌트가 그려지는 최초에만 동작

 

custom Hook 만들기

컨벤션 : 카멜케이스 use{Name}

function useLocalStorage(itemName, value = "") {
    const [state, setState] = React.useState(() => {
      return window.localStorage.getItem(itemName) || value;
    });

    React.useEffect(() => {
      window.localStorage.setItem(itemName, state);
    }, [state]);

    return [state, setState];
}

위와 같이 localStorage에서 데이터를 가져오고, 저장하는 hook을 만들고

const [keyword, setKeyword] = useLocalStorage("keyword");

와 같이 사용할 수 있다.

 

반복되는 기능은 함수화하고, useState, useEffect등의 hook이 반복되면 custom Hook으로 만든다.

 

hook flow이해하기

언제 불리고, 언제 사라지고, 중첩적인 컴포넌트가 있다면 해당 hook의 호출타임은 언제일까?

 

hook의 호출 타이밍

useEffect는 사이드 이펙트이기 때문에, render후에 동작된다.

- render start

- useState

- render end

- useEffect(useEffect끼리는 선언 순서에 따라  달라진다, deps가 빈 배열인 경우 초기1회만 호출)

console에 출력하는 것으로 직접 확인해 볼 수 잇다.

 

자식 컴포넌트가 있는 경우

children이 다 그려지고, useEffect가 다 이뤄지고 난 후에 App의 useEffect가 일어난다.

 

cleanup -> useEffect의 return 하면서 호출되는 부분

React.useEffect(() => {
  console.log("APP useEffect, no deps");

  return () => {
    console.log("APP useEffect [Cleanup], no deps");
  };
});

useEffect가 동작할때 이전 동작을 제거

 

useEffect  : render가 끝난 후, children의 useEffect가 끝난 후

update : useEffect clean up이 끝난 후(부모의 cleanup이 먼저, children의 cleanup이 이후)

 

deps array: deps 내의 값이 변한 경우 

 

Share Link
reply
«   2025/02   »
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