ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ ๊ฐ์ธ ๊ณต๋ถ ํ ์๋ฃ๋ฅผ ๋จ๊ธฐ๊ธฐ ์ํ ๋ชฉ์ ์ผ๋ก ์์ฑํ์ต๋๋ค.
์ ๋ ์นด ๊ธฐ๋ฅ์์ ๋ฒํผ์ ๋๋ฅผ ๋๋ง๋ค ๋ฌผ๊ฒฐ์ ์ง์ฐ๋ ํจ์๊ฐ ๋๋ฌด ๋นจ๋ฆฌ, ๋๋ฌด ๋ง์ด ํธ์ถ๋๋ ๊ฒ์ ๋ง๊ณ ์ ๊ณต๋ถํ๊ฒ ๋์์ต๋๋ค. 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๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
์ง์คํด์๋ฅผ ์ญ์ง ๊ฒฝ์๋๋ก ์๋์ ๊ฐ์ ๋ฌธ์๋งต์ ์ฌ์ฉํ์ฌ 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'),
];
}
- ์ฐธ๊ณ : movable type
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(),
});
- ์ฐธ๊ณ : Firebase ๊ณต์๋ฌธ์