728x90

자바스크립트 구조분해할당과 keys를 얻는 방법에 대해 간략하게 적어둔다.

 

 
const user = {
    name:'홍길동',
    age: 25,
    email:'link2me@gmail.com'
}
 
// 구조 분해 할당 : 필요한 변수만 지정할 수 있다.
const { name, age, email } = user;
console.log(`사용자의 이름은 ${name}입니다.`);
console.log(`${name}의 나이는 ${age}세 입니다.`);
console.log(`${name}의 이메일은 ${email}세 입니다.`);
 
/***
 * Object.keys(obj) – 객체의 키만 담은 배열을 반환.
 * Object.values(obj) – 객체의 값만 담은 배열을 반환
 * Object.entries(obj) – [키, 값] 쌍을 담은 배열을 반환
 */
const keys = Object.keys(user);
console.log(keys); // [ 'name', 'age', 'email' ]
 
console.log(user['email']);
 
const values = keys.map(key => user[key])
console.log(values); // [ '홍길동', 25, 'link2me@gmail.com' ]
 
for(let key in user){
    console.log(`${key} ${user[key]}`);
}
 

 

 

 

728x90
블로그 이미지

Link2Me

,
728x90

JavaScript의 Object.assign()메서드 사용법을 알아보자.

불변성(immutable)을 지켜야 된다면 Object.assign을 사용하는 것 보다 스프레드 연산자를 사용하는 것이 좋다.
Object.assign으로 불변성을 지키려면 target에 항상 {} 빈 객체를 인자로 전달해야 한다.

const userAge = {
    name:'홍길동',
    age:25
}
 
const userEmail = {
    name:'홍길동',
    email:'link2me@gmail.com'
}
 
/***
 * Object.assign(target, ...sources);
 * target : 출처 객체의 속성을 복사해 반영한 후 반환할 객체
 * source : 목표 객체에 반영하고자 하는 속성들을 갖고 있는 객체들
 * 목표 객체의 속성 중 출처 객체와 동일한 키를 갖는 속성의 경우,
 * 그 속성 값은 출처 객체의 속성 값으로 덮어쓴다.
 */
const target = Object.assign({}, userAge, userEmail);
console.log(target);
// { name: '홍길동', age: 25, email: 'link2me@gmail.com' }
console.log(userAge);
// { name: '홍길동', age: 25 }
console.log(target === userAge); // false
 
const a = { k: 123 }
const b = { k: 123 }
console.log(a === b); // false
 

 

 

 
const userAge = {
    name:'홍길동',
    age:25
}
 
const userEmail = {
    name:'홍길동',
    email:'link2me@gmail.com'
}
 
/***
 * Object.assign(target, ...sources);
 * target : 출처 객체의 속성을 복사해 반영한 후 반환할 객체
 * source : 목표 객체에 반영하고자 하는 속성들을 갖고 있는 객체들
 * 목표 객체의 속성 중 출처 객체와 동일한 키를 갖는 속성의 경우,
 * 그 속성 값은 출처 객체의 속성 값으로 덮어쓴다.
 */
const target = Object.assign(userAge, userEmail);
console.log(target);
// { name: '홍길동', age: 25, email: 'link2me@gmail.com' }
console.log(userAge);
// { name: '홍길동', age: 25, email: 'link2me@gmail.com' }
console.log(target === userAge); // true
 
const a = { k: 123 }
const b = { k: 123 }
console.log(a === b); // false (서로 다른 객체)
 

 

728x90
블로그 이미지

Link2Me

,
728x90

한 마디로 클로저란, 함수가 선언될(생성될) 그 당시에 주변의 환경과 함께 갇히는 것을 말한다.
함수가 속한 렉시컬 스코프(Lexical Environment)를 기억하여, 함수가 렉시컬 스코프 밖에서 실행될 때도 이 스코프에 접근할 수 있게 해주는 기능이다.
렉시컬 스코프란 함수가 선언이 되는 위치에 따라서 상위 스코프가 결정되는 스코프다.
내부함수는 외부함수의 지역변수에 접근할 수 있는데 외부함수의 실행이 끝나서 외부함수가 소멸된 이후에도 내부함수가 외부함수의 변수에 접근할 수 있는 것

 

/***
 * 자바스크립트에는 클로저라는 기능이 있다.
 * 클로저는 함수와 그 함수를 둘러싸고 있는 주변의 상태를 기억하는 기능이다.
 * 클로저는 자바스크립트 고유의 개념이 아니라
 * 함수를 일급 객체로 취급하는 함수형 프로그래밍 언어에서 사용되는 중요한 특성이다.
 * 클로저가 가장 유용하게 사용되는 상황은 현재 상태를 기억하고 변경된 최신 상태를 유지하는 것이다.
 */
 
function makeAdd2(v1) {
  // 함수 makeAdd 내에서 내부함수가 선언되고 호출되었다.
  return function (v2) {
    //  이때 내부함수는 자신을 포함하고 있는 외부함수 makeAdd 변수 v1 접근할 수 있다.
    return v1 + v2;
  };
}
 
function makeAdd(v1){
  // 함수 makeAdd 내에서 내부함수 innerFunc가 선언되고 호출되었다.
  let innerFunc = function (v2){
    //  이때 내부함수 innerFunc는 자신을 포함하고 있는 외부함수 makeAdd 변수 v1 접근할 수 있다.
    return v1 + v2;
  }
  return innerFunc;
}
 
const add3 = makeAdd(3);
console.log(add3); // [Function innerFunc]
console.log(add3(10));
const add7 = makeAdd(7);
console.log(add7(10));
 

 

 

 
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>closure</title>
    <script defer src="./main.js"></script>
</head>
<body>
<p>클로저를 사용한 Counting</p>
<button id="inclease">+</button>
<p id="count">0</p>
<script>
    const incleaseBtn = document.getElementById('inclease');
    const count = document.getElementById('count');
 
    const increase = (function () {
        // 카운트 상태를 유지하기 위한 변수
        let counter = 0;
        // 클로저를 반환
        return function () {
            return ++counter;
        };
    }());
 
    incleaseBtn.onclick = function () {
        count.innerHTML = increase();
    };
</script>
</body>
</html>

 

 

728x90
블로그 이미지

Link2Me

,
728x90

일급 객체(First Class citizen)
1. 변수(variable)에 담을 수 있다.
2. 파라미터로 전달할 수 있다.
3. 함수의 반환 값으로 사용할 수 있다.

 

/***
 * first class citizen(1급 객체)
 * 변수에 할당(assignment)할 수 있다.
 * 다른 함수를 인자(argument)로 전달 받는다.
 * 다른 함수의 결과로서 리턴될 수 있다.
 */
 
function mul(num1, num2) {
    return num1 * num2;
}
 
/***
 * func는 매개변수, 이름은 func이건 mul이건 상관없음
 * 매개변수(parameter)로 func를 받았고, 함수(func)를 리턴하기 때문에 고차함수
 * @param func : func()의 매개변수가 2개라면 mulNum()의 매개변수도 2개이여야함
 * @param number1
 * @param number2
 * @returns {*}
 */
function mulNum(func, number1, number2) {
    return func(number1, number2);
}
 
// 전달인자(argument)로 받은 함수인 mul은 콜백함수
let result = mulNum(mul, 34);
console.log(result);
 
// 다른 함수의 결과로 리턴 될 수 있다.
function add(num1) {
    return function (num2) {
        return num1 + num2;
    }
}
 
const rs_add = add(3)(4);
console.log(rs_add);

 

 

728x90

'React > morden javascript' 카테고리의 다른 글

JavaScript Object.assign()  (0) 2023.10.17
Javascript 클로저(Closure)  (0) 2023.10.06
[ES2020] optional chaining  (0) 2022.12.28
[ES6] 비구조화 할당(destructuring assignment)  (0) 2022.12.28
Javascript Array.filter 사용 예제  (0) 2022.12.27
블로그 이미지

Link2Me

,
728x90

Optional Chaining은 ES2020에서 등장한  '?.' 연산자는 체인으로 이루어진 각 참조가 유효한지 명시적으로 검증하지 않고 연결된 객체 체인 내에 깊숙이 위치한 속성 값을 읽을 수 있다.

Node.js의 경우 버전 14부터 지원한다.

 

참조가 null 혹은 undefined여도 에러를 출력하지 않고 undefined 값을 리턴한다.

함수 호출시에도 마찬가지로 값이 없다면 undefined를 리턴한다.

 

옵셔널 체이닝 앞의 변수는 꼭 선언되있어야 한다.

const obj = {
    name'Alice',
    cat: {
        name'Dinah'
    }
};
 
const dogName = obj.dog?.name;
console.log(dogName); // output: undefined
 
console.log(obj.someNonExistentMethod?.()); // output: undefined
 
let arr = [12345]
console.log(arr?.[4]);
console.log(arr?.[5]); // undefined
arr[5= 6;
console.log(arr?.[5]);
 
// optional chaining은 값을 읽고 삭제할때에는 사용할 수 있지만
// 값을 할당할 때는 사용할 수 없다.
let user = {
    age: 35
}
//user?.name = '홍길동'; // undefined = '홍길동'
// undefined가 반환되었을 때 null 병합 연산자(??)를 사용해 기본 값을 할당할 수 있다.
user.name = user?.name ?? '홍길동';
console.log(user.name, user.age);

 

optional chaining 이 브라우저에 따라 동작이 안될 수 있으니 반드시 확인해야 한다.

728x90
블로그 이미지

Link2Me

,
728x90

ES6부터 비구조화 할당(Destructuring Assignment)이라는 새로운 자바스크립트 표현식이 추가되었다.

비구조화할당이란 배열이나 객체의 속성 혹은 값을 해체하여 그 값을 변수에 각각 담아 사용하는 자바스크립트 표현식이다.

 

/***
 * 비구조화 할당의 기본 구조는 좌측에는 변수, 우측에는 해당 변수에 넣어지는 값을 표현한다.
 * 배열의 경우 []를 사용하고, 객체의 경우 {}를 사용한다.
 
 const [변수명1, 변수명2, 변수명3] = [값1, 값2, 값3];
 const [변수명1, 변수명2, 변수명3 = 기본값] = [값1, 값2];
 
 const 배열명 = [값1, 값2, 값3];
 const [변수명1, 변수명2, 변수명3] = 배열명;
 
 const {변수명1,변수명2,변수명3} = {
     속성명1: 값1,
     속성명2: 값2,
     속성명3: 값3
 };
 
*/
 
const arr = [1];
const [a = 10, b = 20= arr;
// 배열 값이 있으면 변수 기본 값은 무시한다.
console.log({ a, b });
 
const fruits = ['apple''banana''cherry''peach']
const [apple, ...etc] = fruits;
console.log(apple);
console.log(etc);

// JSON 객체에서는 우측의 key 값이 좌측의 변수명과 매칭된다.
const { cat, dog, tiger } = {
    cat: 'CAT',
    dog: 'DOG',
    tiger: 'TIGER'
};
 
console.log(cat);
console.log(dog);
console.log(tiger);

전개 연산자(...)를 이용하면 하나의 변수를 할당하고 나머지 값들을 모두 넣어준다.

전개 연산자를 사용하려면 반드시 가장 마지막 요소에 넣어줘야 한다.

나머지 요소의 오른쪽 뒤에 쉼표가 있으면 SyntaxError가 발생한다.
var [a, ...b,] = [1, 2, 3];

 

 

const arr2 = [123];
const [first, ...rest1] = arr2;
console.log(rest1); // 컴마 개수 이후의 모든 나머지 [2,3]
const [aa, bb, cc, ...rest2] = arr2;
console.log(rest2); // 빈 배열 []
 
const obj = { age: 36name'이순신' };
const { age, name } = obj;
console.log({ age, name });
const { ao, bo } = obj; // 객체에 없는 변수를 할당하면??
console.log({ao, bo}); // { ao: undefined, bo: undefined }
 
const obj2 = { age2: undefined, name2: null, grade2: 'A' };
const { age2 = 0, name2 = 'noName', grade2 = 'F' } = obj2;
console.log({ age2, name2, grade2 }); // { age2: 0, name2: null, grade2: 'A' }
// undefined 인 경우에만 기본값으로 대체된다.

 

 

728x90
블로그 이미지

Link2Me

,
728x90

Array filter 메서드는 조건을 만족하는 요소만 모아서 새로운 배열을 반환한다.

const arr = [1581012151620];
 
/***
* Array.prototype.filter() 메서드는 조건을 만족하는 요소만 모아서 새로운 배열을 리턴
 */
const rs1 = arr.filter(x => x % 5 == 0); // 조건 : 5의 배수
console.log(rs1);
 
// filter 메서드 대신 find 메서드를 사용하면 어떤 결과를 반환할까?
console.log(arr.find(x => x % 5 == 0)); // find 메서드는 단 하나의 요소만 리턴
 
console.log(arr.filter((item) => item >= 12)); // 조건 : 12보다 큰 수
 
const users = [
    { name'지민', salary : 7000000 },
    { name'철수', salary : 2500000 },
    { name'재석', salary : 3200000 },
    { name'종민', salary : 4600000 },
];
 
testJson = JSON.stringify(users);
const newJson = JSON.parse(testJson).filter(function(item){
    console.log(item);
    return item.name == "종민";
});
console.log(newJson);
 
// 화살표 함수로 조건을 쉽게 사용 가능
const newUser = users.filter(item => item.name == "종민");
console.log(newUser);
 
const users2 = {
    class : "1-1",
    subject : "English",
    scores : [
        { name : "길동", score : 60 },
        { name : "재섭", score : 80 },
        { name : "현수", score : 100 },
        { name : "희성", score : 70 },
        { name : "광수", score : 40 },
        { name : "혜리", score : 90 }
    ]
};
 
// 점수가 80점 이상인 학생들
const rs3 = users2.scores.filter(item => item.score >= 80);
console.log(rs3);
 
// 점수가 70 ~ 90 사이인 학생들
const rs4 = users2.scores.filter(item => item.score >= 70 && item.score <= 90);
console.log(rs4);

 

 

 

728x90
블로그 이미지

Link2Me

,
728x90

Definition and Usage
map() creates a new array from calling a function for every array element.
map() calls a function once for each element in an array.
map() does not execute the function for empty elements.
map() does not change the original array.

map을 이용하면 원 배열을 변경하지 않고 새로운 배열을 만든다.

map은 forEach와 마찬가지로 Array 각 요소를 순회하며 callback 함수를 실행한다. callback에서 return 되는 값을 배열로 반환한다.

 

const arr = [123];
const new_arr = new Array(123);
 
console.log('arr',arr);
console.log('new_arr',new_arr);
console.log(typeof arr === "object");
console.log(Object.values(arr));
 
// Array map() 함수를 이용하여 배열의 요소들을 변경하여 새로운 배열로 리턴
const arr1 = [12345];
 
const result1 = arr1.map(x => x + 1);
console.log('result1', result1);
 
const result_map = arr1.map(x => x * x);
console.log('result_map',result_map);
 
const result_old = [];
for (i = 0; i < arr1.length; i++) {
   result_old.push(arr1[i] * arr1[i]);
}
console.log('result_old',result_old);
 
const result3 = arr1.map(function (x,index){
   console.log(`arr1[${index}] = ${x}`);
   return x*3;
});
console.log('result3',result3);
 
 
const users = [
   { name'지민', age: 22 },
   { name'철수', age: 32 },
   { name'재석', age: 21 },
   { name'종민', age: 35 },
];
 
// 특정 요소만 재정의
const newUsers = users.map(user => {
   if (user.name === '철수') {
      return { ...user, age: 38 };
   }
   return { ...user };
});
console.log(newUsers);
// keys() is not supported in Internet Explorer 11 (or earlier).
console.log(Object.keys(newUsers));
console.log(Object.values(newUsers));
// The entries() method is not supported in Internet Explorer 11 (or earlier).
console.log(Object.entries(newUsers));
for (const [key, value] of Object.entries(newUsers)) {
   console.log(key, value);
}
 
/***
 * 자바스크립트엔 여덟 가지 자료형(숫자형, bigint형, 문자형, 불린형, 객체형, Null형, Undefined형, 심볼형)이 있다.
 * const 키워드에 객체를 할당하면 당연히 객체를 가리키는 주소 값이 할당된다. 그리고 이 주소 값은 불변이다.
 * 객체는 참조값을 통해 관리되고 있어 객체의 속성 값이 재할당 되더라도 오류가 발생되지 않는다.
 */
users[0].age = 18// const 키워드로 선언된 객체의 속성값은 재할당할 수 있다.
console.log(users);

 

 

 

728x90
블로그 이미지

Link2Me

,
728x90

"카카오 맵 키워드로 장소검색하고 목록으로 표출하기" 로 검색된 결과 URL 이다.

https://apis.map.kakao.com/web/sample/keywordList/

위 UTL 예시에 나온 코드로는 부족하므로 클러스터링 등 내용을 더 찾아서 살을 붙여야 한다.

 

화면 구성을 위해서 아래와 같이 HTML 을 변경한다.

아래 HTML 코드에서 카카오맵 API Key는 삭제했다.

<html>
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex,nofollow"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>카카오지도</title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css">
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/mdb.lite.css">
<link rel="stylesheet" href="/css/jquery-ui.css">
<link rel="stylesheet" href="/css/kakaomap.css"/>
</head>
<body>
<div class="card">
<div class="my-0 mx-2">
    <div class="form-check form-check-inline">
        <button type="button" class="btn btn-outline-primary btn-sm px-2" id="searchToggle">OFF</button>
    </div>
 
    <div class="form-check form-check-inline">
        <p class="fs-4">반경</p>
    </div>
    <div class="form-check form-check-inline">
      <input class="form-check-input" type="radio" name="radius" id="dis1" value="0.5" checked />
      <label class="form-check-label" for="dis1">0.5</label>
    </div>
 
    <div class="form-check form-check-inline">
      <input class="form-check-input" type="radio" name="radius" id="dis2" value="1.0" />
      <label class="form-check-label" for="dis2">1</label>
    </div>
 
    <div class="form-check form-check-inline">
      <input class="form-check-input" type="radio" name="radius" id="dis3" value="1.5" />
      <label class="form-check-label" for="dis3">1.5</label>
    </div>
    <div class="form-check form-check-inline">
      <input class="form-check-input" type="radio" name="radius" id="dis4" value="2.0" />
      <label class="form-check-label" for="dis4">2</label>
    </div>
 
    <div class="form-check form-check-inline">
        <button type="button" class="btn btn-outline-primary btn-sm px-2" id="curLoc">현위치</button>
    </div>
 
</div>
<div class="mt-1 mb-2 mx-2">
    <div class="map_wrap">
        <div id="map" style="width:100%;height:800px;position:relative;overflow:hidden;"></div>
 
        <div id="menu_wrap" class="bg_white">
            <div class="option">
                <div class="form-check form-check-inline">
                    <form onsubmit="searchPlaces(); return false;">
                        <input type="text" value="" id="keyword" size="15"> 
                        <button type="submit">&nbsp;검색</button>
                    </form>
                    <img src="./marker/icon_eraser.png" alt="clear" height="30" width="30" style="margin-left: 10px;" id="eraser">
                </div>
            </div>
            <div id="datacount"></div>
            <hr>
            <ul id="placesList"></ul>
            <div id="pagination"></div>
        </div>
        <div id="dialog" title="지도 Infowindow"></div>
    </div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script type="text/javascript" src="/js/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/js/mdb.lite.min.js"></script>
<script type="text/javascript" src="/js/jquery-ui.js"></script>
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=&libraries=services,clusterer,drawing"></script>
<script type="text/javascript" src="Map.js"></script>
<script>
$("#searchToggle").click(function(){
    // 지도 검색창 ON/OFF
    if($("#menu_wrap").css("display")=="none"){
        $("#menu_wrap").show();
        $("#searchToggle").text('OFF');
    } else {
        $("#menu_wrap").hide();
        $("#searchToggle").text('ON');
    }
});
 
$("input[name='radius']").change(function(){
    searchPlaces();
});
$("#curLoc").click(function(){
    // 현재 지도의 중심좌표 구하기
    searchPlaces();
});
 
$("#eraser").click(function(){
    $("#keyword").val('');
});
</script>
</body>
</html>

 

Map.js

변수는 let 과 const 로 전부 변경하고, Ajax 로 PHP와 연동된 DB 자료를 가져다가 출력하는 걸 만든다.

    // 마커를 담을 배열입니다
    let markers = [];
 
    const mapContainer = document.getElementById('map'), // 지도를 표시할 div
    mapOption = {
        center: new kakao.maps.LatLng(37.566826126.9786567), // 지도의 중심좌표
        level: 12 // 지도의 확대 레벨
    };
 
    // 지도를 생성합니다
    const map = new kakao.maps.Map(mapContainer, mapOption);
 
    // 마커 클러스터러를 생성합니다
    const clusterer = new kakao.maps.MarkerClusterer({
        map: map, // 마커들을 클러스터로 관리하고 표시할 지도 객체
        averageCenter: true// 클러스터에 포함된 마커들의 평균 위치를 클러스터 마커 위치로 설정
        minLevel: 6 // 클러스터 할 최소 지도 레벨
    });
 
    // 일반 지도와 스카이뷰로 지도 타입을 전환할 수 있는 지도타입 컨트롤을 생성합니다
    const mapTypeControl = new kakao.maps.MapTypeControl();
 
    // 지도에 컨트롤을 추가해야 지도위에 표시됩니다
    // kakao.maps.ControlPosition은 컨트롤이 표시될 위치를 정의하는데 TOPRIGHT는 오른쪽 위를 의미합니다
    map.addControl(mapTypeControl, kakao.maps.ControlPosition.TOPRIGHT);
 
    // 지도 확대 축소를 제어할 수 있는  줌 컨트롤을 생성합니다
    const zoomControl = new kakao.maps.ZoomControl();
    map.addControl(zoomControl, kakao.maps.ControlPosition.RIGHTBOTTOM);
 
    // 지도가 이동, 확대, 축소로 인해 중심좌표가 변경되면 마지막 파라미터로 넘어온 함수를 호출하도록 이벤트를 등록합니다
    let getLat = null;
    let getLng = null;
    kakao.maps.event.addListener(map, 'center_changed'function() {
        // 지도의  레벨을 얻어옵니다
        const level = map.getLevel();
        // 지도의 중심좌표를 얻어옵니다
        const latlng = map.getCenter();
        console.log('중심 위도: '+latlng.getLat() + ', 경도: ' + latlng.getLng());
        getLat = latlng.getLat();
        getLng = latlng.getLng();
    });
 
    // 장소 검색 객체를 생성합니다
    const ps = new kakao.maps.services.Places();
 
    // 검색 결과 목록이나 마커를 클릭했을 때 장소명을 표출할 인포윈도우를 생성합니다
    const infowindow = new kakao.maps.InfoWindow({zIndex:1});
 
    // 키워드로 장소를 검색합니다
    searchPlaces();
 
    // 키워드 검색을 요청하는 함수입니다
    function searchPlaces() {
        let keyword = document.getElementById('keyword').value;
        let radius = $("input[name='radius']:checked").val();
 
        $.ajax({
            url : 'ajaxMap.php',
            type : 'GET',
            data : { 'msg': keyword, 'radius':radius, 'lat':getLat, 'lng':getLng },
            dataType: 'json',
            success : function(json) {
                if(json.length == 0) {
                    alert('검색 데이터가 없습니다.');
                    return;
                }
 
                console.log('데이터 갯수 :: ' + json.length);
                displayPlaces(json);
 
                // 클러스터에 마커들을 추가합니다
                clusterer.addMarkers(markers);
 
                var pagination = [ '1''2''3' ];
                displayPagination(pagination);
            },
            error : function(xhr, status, error){
                alert("에러코드 : " + xhr.status); //요청에 실패하면 에러코드 출력
            },
            complete : function() {
                
            }
        });
    }
 
    // 장소검색이 완료됐을 때 호출되는 콜백함수 입니다
    function placesSearchCB(data, status, pagination) {
        if (status === kakao.maps.services.Status.OK) {
            // 정상적으로 검색이 완료됐으면 검색 목록과 마커를 표출합니다
            displayPlaces(data);
 
            // 페이지 번호를 표출합니다
            displayPagination(pagination);
        } else if (status === kakao.maps.services.Status.ZERO_RESULT) {
            alert('검색 결과가 존재하지 않습니다.');
            return;
        } else if (status === kakao.maps.services.Status.ERROR) {
            alert('검색 결과 중 오류가 발생했습니다.');
            return;
        }
    }
 
    // 검색 결과 목록과 마커를 표출하는 함수입니다
    function displayPlaces(places) {
        let listEl = document.getElementById('placesList'),
        menuEl = document.getElementById('menu_wrap'),
        fragment = document.createDocumentFragment(),
        bounds = new kakao.maps.LatLngBounds(),
        listStr = '';
 
        // 검색 결과 목록에 추가된 항목들을 제거합니다
        removeAllChildNods(listEl);
 
        // 지도에 표시되고 있는 마커를 제거합니다
        removeMarker();
 
        const cntEl = document.getElementById('datacount');
        cntEl.innerText = '검색 개수 : ' + places.length;
 
 
        for (let i=0; i<places.length; i++) {
 
            let color_marker = "marker-icon-blue.png";
 
            if (places[i].yn == 0)  { // 없으면 => 빨간색
                color_marker = "marker-icon-red.png";
                if(places[i].isbiz > 0) {
                    color_marker = "marker-icon-green.png";
                }
            } else {
                color_marker = "marker-icon-blue.png";
                if(places[i].isbiz > 0) {
                    color_marker = "marker-icon-orange.png";
                }
            }
 
            // 마커를 생성하고 지도에 표시합니다.
            let idx = places[i].idx; // 절대 var 변수를 선언하면 안된다. 반드시 let 변수를 선언해야 제대로 동작되더라. 개삽질을 엄청했다.
            let title = places[i].idx;
            let placePosition = new kakao.maps.LatLng(places[i].latitude, places[i].longitude);
            let marker = addMarkers(placePosition, color_marker, title);
            let itemEl = getListItem(i, places[i], color_marker); // 검색 결과 항목 Element를 생성합니다
 
            // 검색된 장소 위치를 기준으로 지도 범위를 재설정하기위해 LatLngBounds 객체에 좌표를 추가합니다
            bounds.extend(placePosition);
 
            // 마커와 검색결과
            // 항목에 mouseover 했을때 해당 장소에 인포윈도우에 장소명을 표시합니다. mouseout 했을 때는 인포윈도우를 닫습니다
            (function(marker, title) {
                kakao.maps.event.addListener(marker, 'mouseover'function() {
                    displayInfowindow(marker, title);
                });
 
                kakao.maps.event.addListener(marker, 'mouseout'function() {
                    infowindow.close();
                });
 
                itemEl.onmouseover =  function () {
                    displayInfowindow(marker, title);
                };
 
                itemEl.onmouseout =  function () {
                    infowindow.close();
                };
 
                // 마커에 클릭 이벤트를 등록한다.
                kakao.maps.event.addListener(marker, 'click'function() {
                    //map.panTo(placePosition); // 지도 중심을 부드럽게 이동시킨다.
                    console.log('idx:' + idx);
                    custom_infowindow(idx);
 
                });
 
            })(marker, places[i].bldNM);
 
            fragment.appendChild(itemEl);
        }
 
        // 검색결과 항목들을 검색결과 목록 Elemnet에 추가합니다
        listEl.appendChild(fragment);
        menuEl.scrollTop = 0;
 
        // 검색된 장소 위치를 기준으로 지도 범위를 재설정합니다
        map.setBounds(bounds);
    }
 
    function custom_infowindow(idx){
        $('#dialog').load('infowindow.php?do='+idx, function() {
            $(this).dialog({
                autoOpen : true,
                height : 'auto',
                width : 'auto',
                position: { my: "center", at: "center", of: window },
                title : 'XX정보',
                buttons : {
                    "닫기" : function() {
                        $(this).dialog("close");
                    }
                }
            });
        });
 
    }
 
    // 검색결과 항목을 Element로 반환하는 함수입니다. 위도, 경도, 번호, 건물명, 도로명주소, 지번주소
    function getListItem(index, places, _color) {
        let el = document.createElement('li'),
        itemStr = '<span style="float:left;position:absolute;width:33px; height:31px;margin:10px 0 0 10px;"><img width="31" height="31" src="./marker/' + _color + '"></span>' +
                  '<div class="info">' +
                  '   <h5>' + places.bldNM + '</h5>';
 
        if (places.stAddress) {
            itemStr += '   <span>' + places.stAddress + '</span>' +
                       '   <span class="jibun gray">' +  places.jiAddress  + '</span>';
        } else {
            itemStr += '   <span>' +  places.jiAddress  + '</span>';
        }
 
        itemStr     += '  <span class="tel">' + places.idx  + '</span>' +
                       '</div>';
 
        el.innerHTML = itemStr;
        el.className = 'item';
 
        return el;
    }
 
 
    function addMarkers(position, _color, title) {
        const imageSrc = './marker/' + _color;
        const imageSize = new kakao.maps.Size(3333);
        const imageOptions = {
            offset: new kakao.maps.Point(2769)
        };
 
        const markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOptions)
        // 마커를 생성합니다
        const marker = new kakao.maps.Marker({
            position: position,
            //title: title,
            image: markerImage
        });
 
 
        marker.setMap(map); // 마커가 지도 위에 표시되도록 설정합니다
        markers.push(marker); // 생성된 마커를 배열에 추가합니다
 
        return marker;
    }
 
    // 지도 위에 표시되고 있는 마커를 모두 제거합니다
    function removeMarker() {
        //clusterer.removeMarkers(markers);
        clusterer.clear(); // 추가된 모든 마커 삭제
        for ( let i = 0; i < markers.length; i++ ) {
            markers[i].setMap(null);
        }
        markers = [];
    }
 
    // 검색결과 목록 하단에 페이지번호를 표시는 함수입니다
    function displayPagination(pagination) {
        let paginationEl = document.getElementById('pagination'),
            fragment = document.createDocumentFragment(),
            i;
 
        // 기존에 추가된 페이지번호를 삭제합니다
        while (paginationEl.hasChildNodes()) {
            paginationEl.removeChild (paginationEl.lastChild);
        }
 
        for (i=1; i<=pagination.last; i++) {
            let el = document.createElement('a');
            el.href = "#";
            el.innerHTML = i;
 
            if (i===pagination.current) {
                el.className = 'on';
            } else {
                el.onclick = (function(i) {
                    return function() {
                        pagination.gotoPage(i);
                    }
                })(i);
            }
 
            fragment.appendChild(el);
        }
        paginationEl.appendChild(fragment);
    }
 
    // 검색결과 목록 또는 마커를 클릭했을 때 호출되는 함수. 인포윈도우에 장소명을 표시합니다
    function displayInfowindow(marker, title) {
        const content = '<div style="padding:5px;z-index:1;">' + title + '</div>';
 
        infowindow.setContent(content);
        infowindow.open(map, marker);
    }
 
    // 검색결과 목록의 자식 Element를 제거하는 함수입니다
    function removeAllChildNods(el) {
        while (el.hasChildNodes()) {
            el.removeChild (el.lastChild);
        }
    }
 
 

 

백엔드 PHP 코드는 여기에는 적지 않는다.

화면에 뿌리는 marker 의 개수와 성능은 백엔드 Query를 어떻게 구현하느냐에 따라 달라진다.

가능하면 SELECT 문의 결과를 최소로 하여 원하는 결과를 찾을 수 있게 구현한다.

 

 

 

 

 

 

728x90

'React > morden javascript' 카테고리의 다른 글

Javascript Array.filter 사용 예제  (0) 2022.12.27
Javascript Array.map 사용 예제  (2) 2022.12.27
[Javascript] 정규표현식  (0) 2022.10.08
[Javascript] _cloneDeep()  (0) 2022.10.05
[ES6] Spread 연산자  (0) 2022.10.02
블로그 이미지

Link2Me

,
728x90

React 에서 네이버 지도 API 를 이용하기 위해 간단 테스트하고 적어둔다.

먼저 https://www.ncloud.com/ 사이트에서http://localhost:3000 을 추가했다.

 

 

index.html 에 라이브러리 추가

// index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <script type="text/javascript" src="https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=키추가하세요"></script>
  </body>
</html>
 

 

인증정보에서 Client ID 값을 복사하여 붙여넣기 한다.

 

네이버맵 Sample 구현

- https://navermaps.github.io/maps.js/docs/tutorial-2-Getting-Started.html 에 지도 DOM 요소 지정하기 <div id="map" style="width:100%;height:400px;"></div> 를 포함하도록 되어 있다. return 문 안에 div 태크를 추가한다.

- 지도 띄우는 코드는 useEffect Hook을 이용하여 샘플코드를 아래와 같이 추가한다.

  샘플에 나오는 var 변수를 사용해도 되고, const, let 등으로 변경하여 변수를 사용해도 된다.

- 최상위에 const { naver } = window; 를 반드시 추가 해준다.

 

// App.js
 
import './App.css';
import NaverMapEx1 from "./NaverMapEx1";
 
function App() {
  return (
    <div className="App">
      <NaverMapEx1 />
    </div>
  );
}
 
export default App;
 
 
 
// NaverMapEx1.js
import React, {useEffect, useState} from 'react';
 
const { naver } = window;
const NaverMapEx1 = () => {
    useEffect(() => {
        const container = document.getElementById("map"); // 지도를 표시할 div
 
        // let markerList = [];
        // const HOME_PATH = window.HOME_PATH || '.';
        const position = new naver.maps.LatLng(37.3849483127.1229117);
        const mapOptions = {
            center: position,
            zoom: 17,
            minZoom: 6,
            zoomControl: true,
            zoomControlOptions: {
                position: naver.maps.Position.TOP_RIGHT,
            },
        };
 
        const map = new naver.maps.Map(container, mapOptions);
 
        const markerOptions = {
            position: position.destinationPoint(9015),
            map: map,
            icon: {
                url:'https://navermaps.github.io/maps.js/docs/img/example/ico_pin.jpg',
                //size: new naver.maps.Size(50, 52),
                origin: new naver.maps.Point(00),
                anchor: new naver.maps.Point(2526)
            }
        };
 
        const marker = new naver.maps.Marker(markerOptions);
 
        console.log("loading navermap");
    },[]);
 
    return (
        <div>
            <div id="map" style={{width:'100%', height:'800px' }}></div>
        </div>
    );
};
 
export default NaverMapEx1;
 

 

JavaScript 버전에 나온 예제대로 icon url 을 적었더니 인식이 안된다.

React 에서 이미지 경로를 어떻게 인식시키는지 알아야만 해결이 될 듯 싶다.

 

간단하게 지도 띄우는 것은 가능한데 custom marker 구현과 infowindow까지 구현해봐야 편의성을 알 수 있을 듯 싶다.

728x90

'React > React' 카테고리의 다른 글

React 카카오맵 API 사용 샘플  (0) 2022.10.24
React useMemo & useCallback  (0) 2022.10.24
React useRef 사용 예제  (0) 2022.10.15
React useReducer  (0) 2022.10.13
React-bootstrap Header.js 테스트  (0) 2022.08.21
블로그 이미지

Link2Me

,
728x90

https://developers.kakao.com/ 에 접속하여 앱을 하나 생성하고 Web 사이트를 등록한다.

PC에서 구현하는 테스트 코드이므로 도메인은 http://localhost:3000 을 추가했다.

 

index.html 에 라이브러리 추가

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React 카카오맵</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=%REACT_APP_KAKAO_API%&libraries=services,clusterer,drawing"></script>
  </body>
</html>
 

 

root 폴더에 .env 파일을 생성하고 아래와 같이 Key 값을 저장한다.

JavaScript 키를 복사하여 .env 파일에 붙여넣기 한다.

 

 

카카오맵 Sample 구현

- https://apis.map.kakao.com/web/guide/ 에 지도를 만들 영역 만들기 <div id="map" style="width:500px;height:400px;"></div> 를 포함하도록 되어 있다. return 문 안에 div 태크를 추가한다.

- 지도 띄우는 코드는 useEffect Hook을 이용하여 샘플코드를 아래와 같이 추가한다.

  샘플에 나오는 var 변수를 사용해도 되고, const, let 등으로 변경하여 변수를 사용해도 된다.

- 최상위에 const { kakao } = window; 를 반드시 추가 해준다.

// App.js
import './App.css';
import KakaoMapEx1 from "./KakaoMapEx1";
 
function App() {
  return (
    <div className="App">
        <KakaoMapEx1 />
    </div>
  );
}
 
export default App;
 
 
// KakaoMapEx1.js
import React, {useEffect} from 'react';
 
const { kakao } = window;
 
const KakaoMapEx1 = () => {
    useEffect(() => {
        let markers = [];
        const container = document.getElementById("map"); // 지도를 표시할 div
 
        const options = {
            center: new window.kakao.maps.LatLng(37.566826126.9786567),
            level: 12// 지도의 확대 레벨
        };
 
        const map = new window.kakao.maps.Map(container, options);
 
        const markerPosition  = new kakao.maps.LatLng(37.365264512305174127.10676860117488);
        const marker = new kakao.maps.Marker({
            position: markerPosition
        });
        marker.setMap(map);
 
        // 버튼 클릭에 따라 지도 이동 기능을 막거나 풀고 싶은 경우에는 map.setDraggable 함수를 사용
        function setDraggable(draggable) {
            // 마우스 드래그로 지도 이동 가능여부를 설정
            map.setDraggable(draggable);
        }
 
        console.log("loading kakaomap");
    }, []);
 
    return (
        <div>
            <div id="map" style={{width:'100%', height:'800px',position:'relative', overflow:'hidden' }}></div>
        </div>
    );
};
 
export default KakaoMapEx1;

 

 

728x90

'React > React' 카테고리의 다른 글

React Naver Map API 사용 샘플  (2) 2022.10.25
React useMemo & useCallback  (0) 2022.10.24
React useRef 사용 예제  (0) 2022.10.15
React useReducer  (0) 2022.10.13
React-bootstrap Header.js 테스트  (0) 2022.08.21
블로그 이미지

Link2Me

,
728x90

함수형 컴포넌트는 랜더링 → component 함수 호출 모든 내부 변수 초기화의 순서를 거친다.

컴포넌트가 랜더링 될 때마다 value 라는 변수가 초기화된다.

useMemo를 사용하면 랜더링 → component 함수 호출 → Memoize 된 함수를 재사용하는 동작 순서를 거친다.

memoization이란 기존에 수행한 연산의 결과값을 어딘가에 저장해 두고 동일한 입력이 들어오면 재활용하는 프로그램 기법을 말한다.

 

object는 객체 타입으로 저장될 때 참조 주소값을 저장한다.

const location = { country: isKorea ? '한국' : '미국' }; 육안으로 보면 똑같지만 객체 타입으로 메모리에 저장될 때의 주소는 완전히 달라서 useMemo 를 사용하지 않으면 계속 rendering 될 수 있다.

React rerendering 하는 조건
- props가 변경되었을 때
- state가 변경되었을 때
- 부모 컴포넌트가 rendering 되었을 때
- forceUpdate() 를 실행하였을 때

useEffect, useCallback, useMemo의 모든 종속성은 참조 동일성을 확인한다.
useEffect() 함수는 두 번째 인자로 넘어온 의존 배열이 변경될 때만 첫 번째 인자로 넘어온 함수를 호출한다.

import React, {useEffect, useMemo, useState} from 'react';
 
const UseMemoEx = () => {
    const [number, setNumber] = useState(0);
    const [isKorea, setIsKorea] = useState(true);
 
    const location = useMemo(() => {
        return {
            country: isKorea ? '한국' : '미국'
        }
    }, [isKorea]);
 
    useEffect(() => {
        console.log('useEffect... 호출');
    }, [location]);
 
    return (
        <div>
            <h3>하루에 몇 끼 먹어요?</h3>
            <input
                type="number"
                value={number}
                onChange={(e) => setNumber(e.target.value)}
            />
            <p> 하루 식사 횟수 : {number}</p>
 
            <h3>어느 나라에 있어요?</h3>
            <p>나라: {location.country}</p>
            <button onClick={() => setIsKorea(!isKorea)}>토글</button>
        </div>
    );
};
 
export default UseMemoEx;

 

자식 컴포넌트에서 useEffect가 반복적으로 트리거되는 것을 막고 싶을 때 사용하자.

 

useMemo 는 특정 결과값을 재사용 할 때 사용하는 반면, useCallback 은 특정 함수를 새로 만들지 않고 재사용하고 싶을때 사용한다.

The useCallback and useMemo Hooks are similar. 

The main difference is that useMemo returns a memoized value and useCallback returns a memoized function.

The React useCallback Hook returns a memoized callback function.
The useCallback Hook only runs when one of its dependencies update.

useCallback(fn, deps)
의존성 배열인 deps에 변경을 감지해야할 값을 넣어주게 되면 deps가 변경될 때마다 콜백 함수를 새로 생성한다.

 

 

let x = 3;
let y = 4;
 
// 자바스크립트에서 함수는 객체로 취급한다.
const add1 = (x, y) => x + y;
const add2 = (x, y) => x + y;
 
console.log(add1(x,y)); // 결과 7
console.log(add2(x,y)); // 결과 7
console.log(add1 === add2); // 참조변수 비교 결과 : false

 

 

 
import React, {useCallback, useState} from 'react';
 
function Light({ room, on, toggle }) {
    console.log({ room, on });
    return (
        <button onClick={toggle}>
            {room} {on ? "💡" : "⬛"}
        </button>
    );
}
 
Light = React.memo(Light);
 
const UseCallbackEx = () => {
    const [bedroom, setBedroom] = useState(false);
    const [kitchen, setKitchen] = useState(false);
    const [bath, setBath] = useState(false);
 
    const toggleBedroom = useCallback(() =>
        setBedroom(!bedroom), [bedroom]
    );
    const toggleKitchen = useCallback(() =>
        setKitchen(!kitchen), [kitchen]
    );
    const toggleBath = useCallback(() =>
        setBath(!bath), [bath]
    );
 
    return (
        <div>
            <Light room="주방" on={kitchen} toggle={toggleKitchen} />
            <Light room="욕실" on={bath} toggle={toggleBath} />
            <Light room="침실" on={bedroom} toggle={toggleBedroom} />
        </div>
    );
};
 
export default UseCallbackEx;

참조 : https://www.daleseo.com/react-hooks-use-callback/

 

React Hooks: useCallback 사용법

Engineering Blog by Dale Seo

www.daleseo.com

 

 

 

728x90

'React > React' 카테고리의 다른 글

React Naver Map API 사용 샘플  (2) 2022.10.25
React 카카오맵 API 사용 샘플  (0) 2022.10.24
React useRef 사용 예제  (0) 2022.10.15
React useReducer  (0) 2022.10.13
React-bootstrap Header.js 테스트  (0) 2022.08.21
블로그 이미지

Link2Me

,
728x90

import React, {useRef, useState} from 'react';
 
const UseRef = () => {
    const [renderer, setRenderer] = useState(0); // 숫자 증가시 화면 랜더링 발생
    const countRef = useRef(0); // 숫자 증가해도 화면 랜더링 없음
    let countVar = 0// 화면 랜더링 발생하면 값 초기화 발생
 
    const doRendering = () => {
        setRenderer(renderer + 1);
    }
 
    const increaseRef = () => {
        countRef.current = countRef.current + 1;
        console.log('ref:', countRef.current);
    }
 
    const increaseVar = () => {
        countVar = countVar + 1;
        console.log('var:', countVar);
    };
 
    return (
        <div>
            <p>Ref: {countRef.current}</p>
            <p>Var: {countVar}</p>
            <button onClick={doRendering}>랜더 UP</button>
            <button onClick={increaseRef}>Ref UP</button>
            <button onClick={increaseVar}>Var UP</button>
        </div>
    );
};
 
export default UseRef;

 

import logo from './logo.svg';
import './App.css';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import useWindowWidth from "./hooks/useWindowWidth";
import UseRef from "./components/UseRef";
 
function App() {
    const width = useWindowWidth();
    return (
        <div className="App">
            <header className="App-header">
                <img src={logo} className="App-logo" alt="logo"/>
                <UseRef />
                {width}
            </header>
        </div>
    );
}
 
export default App;

 

 

useEffect 와 useState를 잘못 사용하면 무한 랜더링이 발생할 수 있다.

useRef를 useEffect 와 사용하면 문제가 해결될 수 있으니 알아두자.

 

 

import React, {useRef, useState} from 'react';
 
const UseRefInput = () => {
    const [inputValue, setInputValue] = useState('');
    const useridInput = useRef();
 
    const onRest = () => {
        setInputValue('');
        useridInput.current.focus();
    };
 
    return (
        <div>
            <input type="text" name="userId"
                   ref={useridInput}
                   onChange={(e)=> setInputValue(e.target.value)}
                   placeholder="userID 입력"
                   value={inputValue} />
            <button onClick={onRest}>초기화</button>
            <p>input: {inputValue}</p>
        </div>
    );
};
 
export default UseRefInput;

 

 

728x90

'React > React' 카테고리의 다른 글

React 카카오맵 API 사용 샘플  (0) 2022.10.24
React useMemo & useCallback  (0) 2022.10.24
React useReducer  (0) 2022.10.13
React-bootstrap Header.js 테스트  (0) 2022.08.21
React CORS error 해결 방법  (0) 2022.08.20
블로그 이미지

Link2Me

,
728x90

VSCode 에서 코드 자동완성 기능을 사용하는 방법을 적어둔다.

WebStorm에서는 "코드 자동완성", "Auto Import" 추가 설정없이 기본 내장되어 있어 신경 쓸 필요가 없더라.

 

1. 코드 자동 완성

- VSCode extension 버튼을 클릭하고 "react code snippets"를 입력하고 설치한다.

 

코드 파일에서

- 함수형인 경우 rsc 를 입력하고 탭키를 누르면 자동완성 기본 폼이 만들어진다.

- 클래스형 component인 경우 rcc 를 입력하고 탭키를 누르면 된다.

 

2. Auto Import

인터넷 강의를 듣다보면 VSCode로 설명하는데 import를 직접 추가 해주는 걸 보게 된다.

 

이렇게 추가해주고 나서 VScode를 한번 종료하고 나서 실행이 제대로 되더라.

Use까지만 입력하면 자동으로 바로 아래에 팝업창이 나온다. 선택하면 자동 import가 된다.

 

728x90

'React > React TOOL&TIP' 카테고리의 다른 글

React 프로젝트 실행 및 npm 최신버전 Update  (1) 2022.05.23
블로그 이미지

Link2Me

,

React useReducer

React/React 2022. 10. 13. 23:47
728x90

 

  • state : 현재 상태
  • dispatch : action을 발생시키는 함수
  • reducer : state와 action를 받아 새로운 state를 반환하는 함수
  • initialState : 초기값

 

useReducer 함수에는 첫번째 인자로 reducer 함수를, 두번째 인자로 초기 상태값을 넣어준다.

import React, { useReducer } from 'react';
 
function reducer(state, action) {
    switch (action.type) {
        case 'PLUS':
            return state + 1;
        case 'MINUS':
            return state - 1;
        default:
            return state;
    }
}
 
function Counter() {
    const [number, dispatch] = useReducer(reducer, 0);
 
    const onIncrease = () => {
        dispatch({ type: 'PLUS' });
    };
 
    const onDecrease = () => {
        dispatch({ type: 'MINUS' });
    };
 
    return (
        <div>
            <h1>{number}</h1>
            <button onClick={onIncrease}>+1</button>
            <button onClick={onDecrease}>-1</button>
        </div>
    );
}
 
export default Counter;

 

import logo from './logo.svg';
import './App.css';
import Counter from "./counter";
 
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <Counter />
      </header>
    </div>
  );
}
 
export default App;
 

 

 

 

728x90

'React > React' 카테고리의 다른 글

React useMemo & useCallback  (0) 2022.10.24
React useRef 사용 예제  (0) 2022.10.15
React-bootstrap Header.js 테스트  (0) 2022.08.21
React CORS error 해결 방법  (0) 2022.08.20
React Query String  (0) 2022.06.08
블로그 이미지

Link2Me

,

TypeScript any

React/typescript 2022. 10. 13. 10:41
728x90

TypeScript에는 다른 프로그래밍 언어에는 존재하지 않는 타입들이 존재한다.

 

자바스크립트에서는 아래와 같은 결과를 반환한다.

let value = 10;
console.log(typeof value); // number
console.log(value.length); // undefined

 

타입스크립트에서는 아래와 같이 에러가 발생함을 표시해준다.

밑줄 표시된 부분에 마우스를 가져가면....

TS2339: Property 'length' does not exist on type 'number'.

라는 결과를 보여준다. number 타입은 length 프로퍼티가 존재하지 않는다.

 

문자열인 경우에는 Javascript 와 TypeScript 모두 에러를 반환하지 않는다.

let str = "10";
console.log(typeof str); // string
console.log(str.length); // 2

 

변수 타입을 any 로 지정하면 에러가 사라지는 결 확인할 수 있다.

any is a type that disables type checking and effectively allows all types to be used.

즉 모든 타입을 허용한다는 뜻이다.

 

let u: any = true;
= "string"// Type 'string' is not assignable to type 'boolean'.
Math.round(u); // Argument of type 'boolean' is not assignable to parameter of type 'number'.

any 타입으로 하면 boolean, string, number 모두를 허용하므로 원치 않는 결과가 발생할 수 있다.

 

Javascript 로 변환하여 결과를 출력하면 어떻게 되는지 확인해보자.

// Javascript 에서 아래와 같이 값을 할당하는데 에러를 출력하지 않는다.
let u = true;
= "string"// Error: string 타입은 boolean 타입이 아니라 할당 불가
console.log(Math.round(u)); // NaN

콘솔 로그로 확인해보면 NaN 이란 결과를 출력한다.

 

any 타입지정은 원하지 않는 결과를 초래할 수 있으니 사용하지 않는게 좋다.

TypeScript 에서 경고 출력하는 메시지를 확인하면서 코드를 올바르게 수정하자.

728x90

'React > typescript' 카테고리의 다른 글

타입스크립트(TypeScript) 개요  (0) 2022.10.09
블로그 이미지

Link2Me

,
728x90

타입스크립트(TypeScript)는 자바스크립트(JavaScript)를 기반으로 정적 타입 문법을 추가한 프로그래밍 언어이다.

 

자바스크립트는 C나 Java와 같은 C-family 언어와는 구별되는 아래와 같은 특성이 있다.
- Prototype-based Object Oriented Language
- Scope와 this
- 동적 타입(dynamic typed) 언어 혹은 느슨한 타입(loosely typed) 언어
이와 같은 특성은 클래스 기반 객체지향 언어(Java, C++, C# 등)에 익숙한 개발자를 혼란스럽게 하며 코드가 복잡해질 수 있고 디버그와 테스트 공수가 증가하는 등의 문제를 일으킬 수 있어 특히 규모가 큰 프로젝트에서는 주의하여야 한다.

TypeScript 또한 자바스크립트 대체 언어의 하나로써 자바스크립트(ES5)의 Superset(상위확장)이다. C#의 창시자인 덴마크 출신 소프트웨어 엔지니어 Anders Hejlsberg(아네르스 하일스베르)가 개발을 주도한 TypeScript는 Microsoft에서 2012년 발표한 오픈소스로, 정적 타이핑을 지원하며 ES6(ECMAScript 2015)의 클래스, 모듈 등과 ES7의 Decorator 등을 지원한다.

 

// TypeScript 전역 설치
npm install -g typescript

 

 

TypeScript 파일(.ts)은 브라우저에서 동작하지 않으므로 TypeScript 컴파일러를 이용해 자바스크립트 파일로 변환해야 한다. 최종적으로 런타임에서는 이렇게 출력된 JavaScript 코드를 구동시키게 된다.

tsc script 와 같이 입력하면 script.js 파일이 같은 폴더에 생성된다.

 

자바스크립트 오류

- 실행을 하면 원치 않는 결과를 반환하기도 한다.

const a = 3// 정수
const b = '5'// 문자열
console.log(a + b); // 결과 : 35
console.log(a * b); // 결과 : 15 (원치 않는 결과)

 

타입스크립트에서는

숫자면 숫자, 문자열이면 문자열이라고 타입을 선언해주어서 계산이 작동되지 못하게 하거나, 컴파일 전에 오류 메시지를 띄우게 한다.

위와 같이 에러라고 표시를 해주고 있다.

강제로 tsc ex001.ts 를 터미널 창에서 실행하면.... ES3 버전의 Javascript 파일로 만들어진다.

tsc ex001.ts -t ES2015 를 터미널 창에서 실행하면 ES5 버전의 Javasript 파일로 만들어진다.

 

폴더에 있는 모든 ts 파일을 한꺼번에 js 파일로 만들려면 아래와 같이 하면 된다.

이제부터는 터미널 창에서 tsc 만 입력하면 자동으로 js 파일로 변경해준다.

만약 tsc ex001.ts 라고 입력하면 tsconfig.json이 무시되므로 주의하자.

 

TypeScript는 정적 타입을 지원하므로 컴파일 단계에서 오류를 포착할 수 있는 장점이 있다. 

명시적인 정적 타입 지정은 개발자의 의도를 명확하게 코드로 기술할 수 있다. 이는 코드의 가독성을 높이고 예측할 수 있게 하며 디버깅을 쉽게 한다.

 

 

 

참고하면 도움되는 글

https://yozm.wishket.com/magazine/detail/1376/

 

TypeScript는 어떻게 공부해야 하나요? | 요즘IT

지금 현재 개발하는 상황을 보면 TypeScript는 피할 수 없는 하나의 대세가 된 것 같습니다. TypeScript가 나온 이후로 점점 TypeScript로 만들어지고 있는 라이브러리나 코드의 비중은 높아지고 있고 아

yozm.wishket.com

 

 

 

 

 

 

728x90

'React > typescript' 카테고리의 다른 글

TypeScript any  (0) 2022.10.13
블로그 이미지

Link2Me

,
728x90

자바스크립트 정규표현식 생성

1. 생성자 방식

    RegExp 생성자 함수를 호출하여 사용할 수 있다.

// new RegExg(표현식)
const regexp1 = new RegExp("^abc");
 
// new RegExg(표현식, 플래그)
const regexp2 = new RegExp("^abc""gi");
const regexp1 = new RegExp(/^abc/i); // ES6
const regexp2 = new RegExp(/^abc/'i');
const regexp3 = new RegExp('^abc''i');

 

 

2. 리터럴 방식

// 정규표현식은 /로 감싸진 패턴을 리터럴로 사용한다.
// 정규 표현식 리터럴은 패턴(pettern)과 플래그(flag)로 구성된다.
const regexp1 = /^abc/;  // --> /패턴/
const regexp2 = /^abc/gi; // --> /패턴/플래그

 

 

자바스크립트 메소드

문법   설명
정규식.exec(문자열)                         일치하는 하나의 정보(Array) 반환
정규식.test(문자열)                           일치 여부(Boolean) 반환
문자열.match(정규식)                       일치하는 문자열의 배열(Array) 반환
문자열.search(정규식)                      일치하는 문자열의 인덱스(Number) 반환
문자열.replace(정규식,대체문자)     일치하는 문자열을 대체하고 대체된 문자열(String) 반환
문자열.split(정규식)                          일치하는 문자열을 분할하여 배열(Array)로 반환
생성자_정규식.toString()                  생성자 함수 방식의 정규식을 리터럴 방식의 문자열(String)로 반환

 

 

For example a(?=b) will match the "a" in "ab", but not the "a" in "ac".

Whereas a(?!b) will match the "a" in "ac", but not the "a" in "ab".

const regexr = /.+(?=:)/;  // positive 전방 탐색(lookahead)
const str = 'https://www.abc.com';
console.log(regexr.exec(str));  // 결과 : https
console.log(str.match(regexr)); // 결과 : https

 

const regexr = /.(?!.)/gi; // 부정형 전방탐색(negative lookahead)
const str = '홍길동';
console.log(regexr.exec(str));  // 결과 : 동
console.log(str.replace(regexr, '*')); // 결과 : 홍길*

 

정규표현식 기본적인 이해는 https://www.nextree.co.kr/p4327/ 를 참조하면 도움된다.

https://heropy.blog/2018/10/28/regexp/

728x90

'React > morden javascript' 카테고리의 다른 글

Javascript Array.map 사용 예제  (2) 2022.12.27
카카오 맵 장소 검색 구현 방법  (0) 2022.12.19
[Javascript] _cloneDeep()  (0) 2022.10.05
[ES6] Spread 연산자  (0) 2022.10.02
자바스크립트 Object  (0) 2022.06.11
블로그 이미지

Link2Me

,
728x90

현재 폴더에 package.json 추가된다.
npm init –y

 

개발용 의존성 패키지 설치 : 개발할 때만 필요하다.  --save-dev 대신에 -D
npm install parcel-bundler –D

 

원하는 버전을 명시하여 버전 설치
npm install lodash@4.17.20

최신버전의 정보를 보여준다.
npm info lodash

package.json 이 있는 곳에서 명령어를 입력해야 한다.
npm update lodash

package.json 파일이 있으면 node_module 을 설치할 수 있다.
package.josn 파일과 package-lock.json 파일을 삭제되지 않게 조심해야 한다.
npm install

 

{
  "name""ex01",
  "version""1.0.0",
  "scripts": {
    "dev""parcel index.html",
    "build""parcel build index.html"
  },
  "keywords": [],
  "author""",
  "license""ISC",
  "description""",
  "dependencies": {
    "lodash""^4.17.21"
  },
  "type""module"
}

Cannot use import statement outside a module 와 같은 에러 메시지가 발생하면

위와 같이 package.json에  "type": "module" 을 추가해주면 해결된다.

 

형변환(Type conversion)
=== 일치연산자
== 동등연산자 : 형변환이 발생한다.

 

객체는 참조타입(reference type)이기 때문에 할당 연산자 (=) 를 사용하면 메모리 주소값이 복사된다.

Spread operator 를 사용하여 의도적으로 얕은 복사(Shallow Copy)를 할 수 있다.

깊은 복사는 lodash 모듈을 설치해서 이용하면 편리하다.

loash 에서 제공하는 얕은 복사 함수는 _.clone(object) 이다.

loash 에서 제공하는 깊은 복사 함수는 _.cloneDeep(object) 이다.

import _ from 'lodash';
 
const user = {
    name'홍길동',
    age : 25,
    emails: ['link2me@test.com']
}
 
const copyUser = _.cloneDeep(user);
console.log(copyUser === user); // 메모리 주소가 같은가?
 
user.age = 30;
user.emails.push('jsk005@test.com');
console.log('user', user);
console.log('copyUser', copyUser);

결과

 

 

 

 

 

 

 

 

 

728x90

'React > morden javascript' 카테고리의 다른 글

카카오 맵 장소 검색 구현 방법  (0) 2022.12.19
[Javascript] 정규표현식  (0) 2022.10.08
[ES6] Spread 연산자  (0) 2022.10.02
자바스크립트 Object  (0) 2022.06.11
자바스크립트 호이스팅(Hoisting)  (0) 2022.06.10
블로그 이미지

Link2Me

,
728x90

ES6에서는  '...'와 같이 다소 특이한 형태의 문법이 추가되었다. 
점 3개가 연달아 붙어있는 이 표시는 Spread Opertor(스프레드 오퍼레이터, 전개 연산자)를 나타내는 것으로, 배열, 함수, 객체 등을 다루는 데 있어서 매우 편리하고 재미있는 새로운 기능을 제공한다.

 

const numbersOne = [123];
const numbersTwo = [456];
const numbersCombined = [...numbersOne, ...numbersTwo];

 

 

const numbers = [123456];
 
const [one, two, ...rest] = numbers;

컴마 개수 이후의 값이 rest 값이다.

 

const arr1 = [012];
const arr2 = [345];
 
// (1) 배열 복사
const arr3 = [...arr1]; // arr3은 [0, 1, 2]
 
// (2) 배열에 추가 요소로 넣기
const arr4 = [12, ...arr2, 910]; // arr4는 [1, 2, 3, 4, 5, 9, 10]
 
// (3) 두 배열 이어 붙이기
const arr5 = [...arr1, ...arr2]; // [0, 1, 2, 3, 4, 5];

 

728x90

'React > morden javascript' 카테고리의 다른 글

[Javascript] 정규표현식  (0) 2022.10.08
[Javascript] _cloneDeep()  (0) 2022.10.05
자바스크립트 Object  (0) 2022.06.11
자바스크립트 호이스팅(Hoisting)  (0) 2022.06.10
Javascript this and Class  (0) 2022.06.09
블로그 이미지

Link2Me

,