Skip to content

Latest commit

ย 

History

History
227 lines (166 loc) ยท 9.16 KB

AHYEON.md

File metadata and controls

227 lines (166 loc) ยท 9.16 KB

header

๐Ÿ‘‹ ์•ˆ๋…•ํ•˜์„ธ์š”? ์ €๋Š” ์˜ด๋‡ธ๋‡ธํŒ€์˜ CTO์ž…๋‹ˆ๋‹ค.๐Ÿ‘‹

๐Ÿ›  Tech Stack ๐Ÿ› 

ย  ย  ย 

ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ๊ฐœ์ธ ๊ณต๋ถ€ ํ›„ ์ž๋ฃŒ๋ฅผ ๋‚จ๊ธฐ๊ธฐ ์œ„ํ•œ ๋ชฉ์ ์œผ๋กœ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

Debounce

์œ ๋ ˆ์นด ๊ธฐ๋Šฅ์—์„œ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๋•Œ๋งˆ๋‹ค ๋ฌผ๊ฒฐ์„ ์ง€์šฐ๋Š” ํ•จ์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ๋นจ๋ฆฌ, ๋„ˆ๋ฌด ๋งŽ์ด ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ๋ง‰๊ณ ์ž ๊ณต๋ถ€ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. onClick, onMouseDown์ด๋‚˜ onScroll๊ณผ ๊ฐ™์€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋Š” ์†๋„๋ฅผ ๋‹ค์Œ์˜ ๋ฐฉ๋ฒ•์œผ๋กœ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • throttling : ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ๋นˆ๋„์— ๋”ฐ๋ฅธ ๋ณ€๊ฒฝ ์ƒ˜ํ”Œ๋ง(ํ•จ์ˆ˜๊ฐ€ ์ฃผ์–ด์ง„ ์‹œ๊ฐ„ ๋™์•ˆ์— ํ•œ ๋ฒˆ ์ด์ƒ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ๋ง‰์Šต๋‹ˆ๋‹ค.)
  • debouncing : ๋น„ํ™œ์„ฑ ์ฃผ๊ธฐ ์ดํ›„์— ๋ณ€๊ฒฝ ์ ์šฉ(ํ•จ์ˆ˜๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ํ˜ธ์ถœ๋œ ํ›„ ํŠน์ • ์‹œ๊ฐ„๊นŒ์ง€ ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค.)

๋ฌผ๊ฒฐ์ด ํผ์ง€๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ง€์šฐ๋Š” ํ•จ์ˆ˜๋ฅผ ์ผ์ • ์‹œ๊ฐ„ ๋ง‰๊ธฐ์œ„ํ•ด debouncing์„ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ํ”„๋กœ์ ํŠธ ๋•Œ์—๋Š” API์š”์ฒญ๊ณผ ๊ฐ™์€ ๋น„์‹ผ ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ๋•Œ ์‘์šฉํ•ด ๋ณด๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

const useDebouncedRippleCleanUp = (rippleCount, duration, cleanUpFunction) => {
  useLayoutEffect(() => {
    let bounce = null;
    if (rippleCount > 0) {
      clearTimeout(bounce);
      bounce = setTimeout(() => {
        cleanUpFunction();
        clearTimeout(bounce);
      }, duration * 2);
    }
    return () => clearTimeout(bounce);
  }, [rippleCount, duration, cleanUpFunction]);
};

const ShoutPage = () => {
  useDebouncedRippleCleanUp(ripples.length, 1000, () => {
    setRipples([]);
    setMyNeighbor([]);
  });
    
    ...
    

์—ฌ๊ธฐ์—์„œ setTimeout์€ ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚œ ํ›„์— ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ์ฒ˜๋ฆฌํ•˜๋Š” ์—ญํ• ์„ ํ•˜๋ฉฐ, clearTimeout์€ setTimeout์„ ์ทจ์†Œํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

Geohash

์œ ๋ ˆ์นด์—์„œ ๋‚ด ์ฃผ๋ณ€ ์œ„์น˜์˜ ์œ ์ €๋“ค๊ณผ ์†Œํ†ตํ•˜๊ธฐ ์œ„ํ•ด Geohash๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

์ง€์˜คํ•ด์‹œ๋ฅผ ์‹ญ์ง„ ๊ฒฝ์œ„๋„๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ์ž๋งต์„ ์‚ฌ์šฉํ•˜์—ฌ 32์ง„๋ฒ•์œผ๋กœ ํ•ด์‹œ๊ฐ’์„ ํ•ด์„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Decimal 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Base 32 0 1 2 3 4 5 6 7 8 9 b c d e f g
Decimal 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
Base 32 h j k m n p q r s t u v w x y z

ezs42๋ผ๋Š” Geohash ๊ฐ’์ด ์žˆ๋‹ค๊ณ  ํ•˜๋ฉด ์•„๋ž˜ ํ‘œ์— ์˜ํ•ด์„œ "01101 11111 11000 00100 00010"๋กœ ํ‘œํ˜„์ด ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ๊ฐ€์žฅ ์™ผ์ชฝ์— ์žˆ๋Š” 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ ๋‘์นธ์”ฉ ์˜ค๋ฅธ์ชฝ ์ด๋™ํ•˜๋ฉด์„œ concatํ•˜๋ฉด 011...์ด ๋‚˜์˜ค๊ณ  ์ด ๊ฐ’์€ ๊ฒฝ๋„, ๊ฐ€์žฅ ์™ผ์ชฝ์— ์žˆ๋Š” 0์—์„œ ํ•œ์นธ ์˜†์— ์žˆ๋Š” 1๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ ๋‘์นธ์”ฉ ์˜ค๋ฅธ์ชฝ ์ด๋™ํ•˜๋ฉด์„œ concatํ•˜๋ฉด 101...์ด ๋‚˜์˜ค๊ณ  ์ด ๊ฐ’์€ ์œ„๋„๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

๊ฒฝ๋„๋Š” 0111110000000, ์œ„๋„๋Š” 101111001001์ž…๋‹ˆ๋‹ค.

bit min mid max val err1
1 90.000 0.000 90.000 45.000 45.000
0 0.000 45.000 90.000 22.500 22.500
1 0.000 22.500 45.000 33.750 11.250
1 22.500 33.750 45.000 39.375 5.625
... ... ... ... ... ...

์ถœ์ฒ˜: https://www.internetmap.kr/entry/geohash [๊ณต๊ฐ„์ •๋ณด์™€ ์ธํ„ฐ๋„ท์ง€๋„]

์ด๊ฒƒ์„ ์™ผ์ชฝ์—์„œ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์ฝ์–ด๊ฐ€๋ฉด์„œ ๋ฒ”์œ„๋ฅผ ์ขํ˜€๊ฐ€๋Š” ๊ณผ์ •์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์œ„๋„๋ฅผ ์˜ˆ๋ฅผ ๋“ค์–ด๋ณด๋ฉด 1์ด๋ฉด ์˜ค๋ฅธ์ชฝ, 0์ด๋ฉด ์™ผ์ชฝ์„ ์„ ํƒํ•ด์„œ ๋ฒ”์œ„๋ฅผ ์ขํ˜€๊ฐ‘๋‹ˆ๋‹ค. ์œ„๋„๋Š” ์ฒ˜์Œ ์‹œ์ž‘ํ• ๋• -90 ~ +90์ž…๋‹ˆ๋‹ค. ๋น„ํŠธ๊ฐ’์ด 0์ด๋ฉด -90 ~ 0, 1์ด๋ฉด 0 ~ +90์ด ๋ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ : ์กฐ๊ธ‰ํ•˜์ง€๋ง๊ณ  ์ฒœ์ฒœํžˆ

์ฐธ๊ณ  : ๊ณต๊ฐ„์ •๋ณด์™€ ์ธํ„ฐ๋„ท์ง€๋„

const base32 = '0123456789bcdefghjkmnpqrstuvwxyz';
/**
 * ์ฃผ์–ด์ง„ ๋ฐฉํ–ฅ(direction)์œผ๋กœ ์ธ์ ‘ํ•œ cell ๋ฐ˜ํ™˜
 * geohash - ์ค‘์‹ฌ์ด ๋˜๋Š” cell
 * direction - geohash์—์„œ์˜ ๋ฐฉํ–ฅ (N/S/E/W).
 * @returns {string} Geocode of adjacent cell.
 */
function adjacent(geohash, direction) {
    geohash = geohash.toLowerCase();
    direction = direction.toLowerCase();

    if (geohash.length == 0) throw new Error('Invalid geohash');
    if ('nsew'.indexOf(direction) == -1) throw new Error('Invalid direction');

    const neighbour = {
        n: [ 'p0r21436x8zb9dcf5h7kjnmqesgutwvy', 'bc01fg45238967deuvhjyznpkmstqrwx' ],
        s: [ '14365h7k9dcfesgujnmqp0r2twvyx8zb', '238967debc01fg45kmstqrwxuvhjyznp' ],
        e: [ 'bc01fg45238967deuvhjyznpkmstqrwx', 'p0r21436x8zb9dcf5h7kjnmqesgutwvy' ],
        w: [ '238967debc01fg45kmstqrwxuvhjyznp', '14365h7k9dcfesgujnmqp0r2twvyx8zb' ],
    };
    
    const border = {
        n: [ 'prxz',     'bcfguvyz' ],
        s: [ '028b',     '0145hjnp' ],
        e: [ 'bcfguvyz', 'prxz'     ],
        w: [ '0145hjnp', '028b'     ],
    };

    const lastCh = geohash.slice(-1);    // last character of hash
    let parent = geohash.slice(0, -1); // hash without last character

    const type = geohash.length % 2;

    // check for edge-cases which don't share common prefix
    if (border[direction][type].indexOf(lastCh) != -1 && parent != '') {
        parent = adjacent(parent, direction);
    }

    // append letter for direction to parent
    return parent + base32.charAt(neighbour[direction][type].indexOf(lastCh));
}


/*
 @returns {{n,ne,e,se,s,sw,w,nw: string}}
 */
export function neighbours(geohash) {
    return [
        geohash,
        adjacent(geohash, 'n'),
        adjacent(adjacent(geohash, 'n'), 'e'),
        adjacent(geohash, 'e'),
        adjacent(adjacent(geohash, 's'), 'e'),
        adjacent(geohash, 's'),
        adjacent(adjacent(geohash, 's'), 'w'),
        adjacent(geohash, 'w'),
        adjacent(adjacent(geohash, 'n'), 'w'),
    ];
}

Firestore

Cloud Firestore๋Š” ํด๋ผ์šฐ๋“œ์— ํ˜ธ์ŠคํŒ…๋˜๋Š” NoSQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. ๊ฐ„ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ‘œํ˜„ํ˜• ์ฟผ๋ฆฌ๋ฅผ ์ง€์›ํ•˜๊ณ , ์‹ค์‹œ๊ฐ„ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์—…๋ฐ์ดํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ๋งˆ๋‹ค ์•ฑ ๋ฐ์ดํ„ฐ๋ฅผ ์ตœ์‹  ์ƒํƒœ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์œ ์ €๊ฐ„์˜ ์ƒํ˜ธ์ž‘์šฉ์ด ํ•„์š”ํ•œ ์œ ์‚ฌ ์ฑ„ํŒ… ์„œ๋น„์Šค์ธ ์œ ๋ ˆ์นด๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

์ดˆ๊ธฐํ™”

ํ”„๋กœ์ ํŠธ์— ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ firestore ์ธ์Šคํ„ด์Šค๋ฅผ ์ดˆ๊ธฐํ™” ํ•ด์ค๋‹ˆ๋‹ค.

import firebase from "firebase/app";
import 'firebase/firestore';

firebase.initializeApp({
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
  projectId: '### CLOUD FIRESTORE PROJECT ID ###'
});

var db = firebase.firestore();

๋ฐ์ดํ„ฐ์ถ”๊ฐ€

  • ๋‹จ์ผ ๋ฌธ์„œ๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ ๋ฎ์–ด์“ฐ๋ ค๋ฉด set()์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. set()์€ ๋ฌธ์„œ๊ฐ€ ์—†์œผ๋ฉด ์ƒˆ๋กœ ๋งŒ๋“ค๊ณ  ์žˆ์œผ๋ฉด ์ƒˆ๋กœ ์ œ๊ณตํ•œ ๋‚ด์šฉ์„ ๋ฎ์–ด์”๋‹ˆ๋‹ค. set()์„ ์‚ฌ์šฉํ•ด์„œ ๋ฌธ์„œ๋ฅผ ๋งŒ๋“ค ๋•Œ๋Š” ๋งŒ๋“ค ๋ฌธ์„œ์˜ ID๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์‹œ์—์„  Email์„ ID๋กœ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋Ÿฌ๋‚˜ ๋ฌธ์„œ์— ์œ ์˜๋ฏธํ•œ ID๋ฅผ ๋‘์ง€ ์•Š๊ณ  ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋„๋ก ํ•  ๋•Œ์—๋Š” add()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
const data = {
  nickname: Nickname,
  avatar: avatarId,
  lat: lat, //y
  lng: lng, //x
  geohash: geofire.geohashForLocation([lat, lng]).substring(0, 5),
};
firestore.collection("users").doc(Email).set(data);
  • ์ „์ฒด ๋ฌธ์„œ๋ฅผ ๋ฎ์–ด์“ฐ์ง€ ์•Š๊ณ  ๋ฌธ์„œ์˜ ์ผ๋ถ€ ํ•„๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ ค๋ฉด update()๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
const data = {
  nickname: nickname,
  avatar: avatarId,
};
firestore.collection("users").doc(userEmail).update(data);
  • ๋ฌธ์„œ๊ฐ€ ์ž‘์„ฑ๋˜๋Š” ์‹œ๊ฐ„์„ ํƒ€์ž„์Šคํƒฌํ”„๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
const data = {
    geohash: pos,
    message: {
        content: myMessage,
        createdAt: firebase.firestore.FieldValue.serverTimestamp(),
    },
};
firestore.collection("users").doc(userEmail).update(data);
  • ๋ฌธ์„œ์˜ ํŠน์ • ํ•„๋“œ๋ฅผ ์‚ญ์ œํ•˜๋ ค๋ฉด ๋ฌธ์„œ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ๋•Œ FieldValue.delete()๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
var userRef = firestore.collection("users").doc(userEmail);
userRef.update({
    message: firebase.firestore.FieldValue.delete(),
});