[JavaScript30] ๐Ÿฝ 15. LocalStorage

์กฐ์ค€ํ˜•ยท2021๋…„ 7์›” 10์ผ
0

JavaScript30

๋ชฉ๋ก ๋ณด๊ธฐ
15/30

๐Ÿฝ 15. LocalStorage

๋ฆฌ์ŠคํŠธ์— ์•„์ดํ…œ์„ ์ถ”๊ฐ€ํ•˜๊ณ , ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜์—ฌ ํŽ˜์ด์ง€์— ์ถœ๋ ฅํ•˜๊ธฐ

์‹คํ–‰ํ™”๋ฉด

์ดˆ๊ธฐ์ฝ”๋“œ

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>LocalStorage</title>
  <link rel="stylesheet" href="style_JuneHyung.css">
</head>
<body>
  <!--
      Fish SVG Cred:
      https://thenounproject.com/search/?q=fish&i=589236
   -->

   <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve"><g><path d="M495.9,425.3H16.1c-5.2,0-10.1,2.9-12.5,7.6c-2.4,4.7-2.1,10.3,0.9,14.6l39,56.4c2.6,3.8,7,6.1,11.6,6.1h401.7   c4.6,0,9-2.3,11.6-6.1l39-56.4c3-4.3,3.3-9.9,0.9-14.6C506,428.2,501.1,425.3,495.9,425.3z M449.4,481.8H62.6L43,453.6H469   L449.4,481.8z"/><path d="M158.3,122c7.8,0,14.1-6.3,14.1-14.1V43.4c0-7.8-6.3-14.1-14.1-14.1c-7.8,0-14.1,6.3-14.1,14.1v64.5   C144.2,115.7,150.5,122,158.3,122z"/><path d="M245.1,94.7c7.8,0,14.1-6.3,14.1-14.1V16.1c0-7.8-6.3-14.1-14.1-14.1C237.3,2,231,8.3,231,16.1v64.5   C231,88.4,237.3,94.7,245.1,94.7z"/><path d="M331.9,122c7.8,0,14.1-6.3,14.1-14.1V43.4c0-7.8-6.3-14.1-14.1-14.1s-14.1,6.3-14.1,14.1v64.5   C317.8,115.7,324.1,122,331.9,122z"/><path d="M9.6,385.2c5.3,2.8,11.8,1.9,16.2-2.2l50.6-47.7c56.7,46.5,126.6,71.9,198.3,71.9c0,0,0,0,0,0   c87.5,0,169.7-36.6,231.4-103.2c5-5.4,5-13.8,0-19.2c-61.8-66.5-144-103.2-231.4-103.2c-72,0-142.2,25.6-199,72.5l-50-47.1   c-4.4-4.1-10.9-5-16.2-2.2c-5.3,2.8-8.3,8.7-7.4,14.6l11.6,75L2.2,370.6C1.3,376.5,4.2,382.4,9.6,385.2z M380.9,230.8   c34.9,14.3,67.2,35.7,95.3,63.6c-10.1,10-20.8,19.2-31.9,27.5c-22.4-3.3-29.6-8.8-30.7-9.7c-4-5.7-11.8-7.7-18.1-4.4   c-6.9,3.6-9.5,12.2-5.9,19.1c1.9,3.5,7.3,10.3,22.4,16c-10.1,5.7-20.5,10.7-31.1,15.1C352.4,320.2,352.4,268.6,380.9,230.8z    M36.3,255.6l29.4,27.7c5.3,5,13.6,5.1,19.1,0.3c53.2-47.6,120.7-73.7,190-73.7c26.9,0,53.2,3.9,78.5,11.3   c-29.3,44.6-29.3,102,0,146.6c-25.3,7.4-51.6,11.3-78.5,11.3c-69,0-136.3-26-189.4-73.2c-2.7-2.4-13.4-6.3-19.1,0.3l-30.1,28.3   l5.7-40C42.2,293,36.3,255.6,36.3,255.6z"/><circle cx="398.8" cy="273.8" r="14.1"/></g></svg>

  <div class="wrapper">
    <h2>LOCAL TAPAS</h2>
    <p></p>
    <ul class="plates">
      <li>Loading Tapas...</li>
    </ul>
    <form class="add-items">
      <input type="text" name="item" placeholder="Item Name" required>
      <input type="submit" value="+ Add Item">
    </form>
  </div>

<script>
  const addItems = document.querySelector('.add-items');
  const itemsList = document.querySelector('.plates');
  const items = [];

</script>


</body>
</html>

์ดˆ๊ธฐํ™”๋ฉด

๐ŸŒ ์ƒˆ๋กœ ์•Œ๊ฒŒ ๋œ ๊ฒƒ

๐Ÿ‘‰ ๊ฐœ๋ฐœ์ž๋„๊ตฌ preserve log

์ฝ˜์†” ์ฐฝ์˜ ๋‚ด์šฉ์€ ์›นํŽ˜์ด์ง€๊ฐ€ ๋‹ค์‹œ ๋กœ๋“œ๋˜๊ฑฐ๋‚˜ ๋ฆฌํ”„๋ ˆ์‹œ ๋˜๋ฉด ๋ชจ๋‘ ์‚ฌ๋ผ์ง€๊ณ  ์ดˆ๊ธฐํ™”๋˜๋Š”๋ฐ
๊ฐœ๋ฐœ์ž๋„๊ตฌ์˜ preserve log๋ฅผ ์ฒดํฌํ•ด๋‘๋ฉด ํŽ˜์ด์ง€๊ฐ€ ๋‹ค์‹œ ๋กœ๋“œํ•ด๋„ ์ฝ˜์†” ์ฐฝ์˜ ๋กœ๊ทธ ๋‚ด์šฉ์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€๋˜๊ฒŒ ๋œ๋‹ค.

๋งค๋ฒˆ ํŽ˜์ด์ง€๋ฅผ ๋ฆฌ๋กœ๋“œ ํ•˜๋ฉด์„œ ํŠน์ • ์กฐ๊ฑด์„ ๋‹ฌ๋ฆฌํ•ด ๋กœ๊ทธ๋ฅผ ๋น„๊ตํ•ด ๋ณผ ๋•Œ ์œ ์šฉ.

์ฐธ๊ณ  : https://velog.io/@yeoj1n/Chrome-๊ฐœ๋ฐœ์ž-๋„๊ตฌ-์„ค๋ช…์„œ-NHN-FORWARD-2020

๐Ÿ‘‰ e.preventDefault

์ด๋ฒคํŠธ๋ฅผ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ, ์ด๋ฒคํŠธ์˜ ์ „ํŒŒ๋ฅผ ๋ง‰์ง€์•Š๊ณ  ๊ทธ ์ด๋ฒคํŠธ๋ฅผ ์ทจ์†Œํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฒคํŠธ๋ฅผ ์ทจ์†Œํ•˜๋Š” ๋„์ค‘ preventDefault๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ๊ตฌํ˜„์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋˜๋Š” ๊ธฐ์กด์˜ ์•ก์…˜์ด ๋™์ž‘ํ•˜์ง€ ์•Š๊ฒŒ๋˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

preventDefault๋Š” DOM์„ ํ†ตํ•œ ์ด๋ฒคํŠธ์˜ ์ „ํŒŒ๋ฅผ ๋ง‰์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ „ํŒŒ๋ฅผ ๋ง‰์„๋•Œ๋Š” event.stopPropagation์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

์ฐธ๊ณ  : https://developer.mozilla.org/ko/docs/Web/API/Event/preventDefault

๐Ÿ‘‰ Array.prototype.map()

map()๋ฉ”์„œ๋“œ๋Š” ๋ฐฐ์—ด ๋‚ด์˜ ๋ชจ๋“  ์š”์†Œ ๊ฐ๊ฐ์— ๋Œ€ํ•ด ์ฃผ์–ด์ง„ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ์•„ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•จ.

์ด๋ฒˆ ์˜ˆ์ œ์˜ ๊ฒฝ์šฐ liํƒœ๊ทธ๋ฅผ ๋ฆฌ์ŠคํŠธ์— ๋„ฃ๋Š”๋‹ค.

์ฐธ๊ณ  : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map

๐ŸŒ ๊ณผ์ •

๊ธฐ๋ณธ ๋ณ€์ˆ˜

  const addItems = document.querySelector('.add-items');
  const itemsList = document.querySelector('.plates');
  const items = [];

๐Ÿ‘‰ 1. ์•„์ดํ…œ์„ ์ถ”๊ฐ€ํ•˜๋Š” ํ•จ์ˆ˜ ์ƒ์„ฑ

 function addItem(e){
     e.preventDefault();
     // console.log('Hello');
     const text = (this.querySelector('[name=item]')).value;

     const item = {
         // text: text,
         text,
         done: false,
     }
     // console.log(item);
     items.push(item);
     populateList(items, itemsList);
     // localStorage.setItem('items', items);
     localStorage.setItem('items', JSON.stringify(items));
     // ํ›„์— JSON.parse()ํ•˜๊ฒŒ๋˜๋ฉด ๋ฐฐ์—ด์•ˆ์˜ ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ๋‚˜์˜ด.
     this.reset();
 }

addItems.addEventListener('submit', addItem);
  • preventDefault()๋ฅผ ์ด์šฉํ•˜์—ฌ ์ด๋ฒคํŠธ๋ฅผ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ, ์ด๋ฒคํŠธ์˜ ์ „ํŒŒ๋ฅผ ๋ง‰์ง€์•Š๊ณ  ๊ทธ ์ด๋ฒคํŠธ๋ฅผ ์ทจ์†Œํ•จ.

  • text์— ํ…์ŠคํŠธ๋ฅผ ์ƒˆ๋กœ ์ž…๋ ฅ์„ ํ•ด์คฌ์„๋•Œ name์˜ value๊ฐ’์„ ์ €์žฅํ•˜๊ณ  item ๊ฐ์ฒด์— ์œ„์—์„œ ๋งŒ๋“  text ๊ฐ’์„ ๋‹ด๊ณ , done์†์„ฑ์— false๋ฅผ ๋‹ด๋Š”๋‹ค

  • localStorage์— items๋ฅผ ๋„ฃ๊ณ , reset()์‹œ์ผœ text๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

toString๊ณผ stringify

toString์„ ํ•˜๊ฒŒ๋˜๋ฉด [object Object]๋กœ ๋ณด์ด์ง€๋งŒ, JSON.stringify()๋ฅผ ํ•˜๊ฒŒ๋˜๋ฉด ํ…์ŠคํŠธ๋กœ ๋“ค์–ด๊ฐ€๊ฒŒ ๋œ๋‹ค.

๊ทธ๋ž˜์„œ localStorage์— setํ• ๋•Œ๋Š” JSON.stringify()๋กœ ๋„ฃ๊ณ , ๊ฐ€์ ธ์˜ฌ ๋•Œ parse๋ฅผ ํ•จ.

items๋ฅผ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์—์„œ items๋ฅผ ๊ฐ€์ ธ์™€ parseํ•˜๊ฑฐ๋‚˜ ๋นˆ๋ฐฐ์—ด๋กœ ๋‘ .

const items = JSON.parse(localStorage.getItem('items')) || [];

๐Ÿ‘‰ 2. ์ถ”๊ฐ€ํ•œ ์•„์ดํ…œ์„ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณด์—ฌ์ฃผ๋Š” ํ•จ์ˆ˜

// input๋ฐ•์Šค์˜ ์ด๋ชจํ‹ฐ์ฝ˜์€ css์— ๋“ฑ๋ก๋˜์žˆ์Œ.
function populateList(plates = [], platesList){
    platesList.innerHTML = plates.map((plate, i)=>{
        return `
            <li>
            	<input type="checkbox" data-index=${i} id="item${i}" ${plate.done ? 'checked' : ''}/>
            	<label for="item${i}">${plate.text}</label>
            </li>
`
    }).join('');
}

์ฒดํฌ ์‹œ ๋งˆ๋‹ค ์ด๋ชจํ‹ฐ์ฝ˜์„ ๋ณ€๊ฒฝํ•จ.

.plates input + label:before {
    content: 'โฌœ๏ธ';
    margin-right: 10px;
}

.plates input:checked + label:before {
    content: '๐ŸŒฎ';
}

๐Ÿ‘‰ 3. ์ฒดํฌ ์—ฌ๋ถ€๋ฅผ ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜

function toggleDone(e){
    if(!e.target.matches('input')) return; // skip this unless it's an input;
    // console.log(e.target);
    const el = e.target;
    // console.log(el.dataset.index); // index ํ™•์ธ
    const index = el.dataset.index;
    items[index].done = !items[index].done;
    localStorage.setItem('items', JSON.stringify(items));
    populateList(items, itemsList);
}

์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ inputํƒœ๊ทธ๊ฐ€ ์•„๋‹Œ๊ฒจ์šฐ ๊ทธ๋ƒฅ ๋„˜๊ธด๋‹ค.

if(!e.target.matches('input')) return; // skip this unless it's an input;

ํ•ด๋‹น ํƒ€๊นƒ์˜ done์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ , ๋‹ค์‹œ localStorage์— setํ•จ.

items[index].done = !items[index].done;
localStorage.setItem('items', JSON.stringify(items));populateList(items, itemsList);

๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ƒˆ๋กœ๊ณ ์นจ์—๋„ ๊ฐ’์ด ์œ ์ง€๊ฐ€ ๋œ๋‹ค.

๐Ÿ‘‰ 4. ํ•จ์ˆ˜ ์‹คํ–‰

addItems.addEventListener('submit', addItem);
itemsList.addEventListener('click', toggleDone);populateList(items, itemsList);
profile
๊นƒํ—ˆ๋ธŒ : github.com/JuneHyung

0๊ฐœ์˜ ๋Œ“๊ธ€