Nomard Life

miniProject - 사용자정보 관리 본문

Develop

miniProject - 사용자정보 관리

Dev_Charlotte 2024. 4. 16. 15:27
728x90
2024.04.16.화

자바스크립트 12일차 ( 총 17일차 )


과제 정보

주제 : 객체리터럴과 localstorage를 이용하여 사용자 정보 저장하기

기본 요구사항

  1. 객체 리터럴을 이용해 사용자 정보를 정의해야합니다.
  2. JSON.stringify() 메서드를 이용해 객체를 JSON 형식의 문자열로 변환해야합니다.
  3. JSON.parse() 메서드를 이용해 JSON 형식의 문자열을 객체로 변환해야합니다.
  4. localstorage.getItem() 메서드를 이용해 사용자 정보를 불러와야합니다.
  5. localstorage.setItem() 메서드를 이용해 사용자 정보를 저장해야합니다.
  6. 개발자 도구 Application/Local Storage 에서 저장한 사용자 정보를 확인해야합니다.

html

<h1>사용자 정보 관리</h1>
<label for="nameInput">이름:</label>
<input type="text" id="nameInput" /><br /><br />
<label for="emailInput">이메일:</label>
<input type="email" id="emailInput" /><br /><br />
<button onclick="saveUserInfo()">저장</button>

<div id="userInfo"></div>

javascript

function saveUserInfo() {
  const name = document.getElementById('nameInput').value;
  const email = document.getElementById('emailInput').value;
  // 'name'과'email'을 키로 사용하는 객체 리터럴 userInfo를 생성
  // 로컬스토리지에 사용자의 정보를 저장

  document.getElementById(
    'userInfo'
  ).innerText = `이름: ${name}, 이메일: ${email}`;
}
// 로컬 스토리지에서 사용자 정보 불러오는 코드

// 페이지 로드 시 저장된 사용자 정보가 있으면 화면에 표시
if (savedUserInfo.name && savedUserInfo.email) {
  document.getElementById(
    'userInfo'
  ).innerText = `이름: ${savedUserInfo.name}, 이메일: ${savedUserInfo.email}`;
}

’name'과'email'을 키로 사용하는 객체 리터럴 userInfo를 생성

const userInfo = {
    name: name,
    email: email,
};

로컬스토리지에 사용자의 정보를 저장

localStorage.setItem('user', JSON.stringify(userInfo));

로컬 스토리지에서 사용자 정보 불러오는 코드

const savedUserInfo = JSON.parse(localStorage.getItem('user'));

입력하고 나니
script.js:35 Uncaught TypeError: Cannot set properties of null (setting 'innerText') 에러가 발생했다.

if (savedUserInfo.name && savedUserInfo.email) {
  document.getElementById(
    'userInfo'
  ).innerText = `이름: ${savedUserInfo.name}, 이메일: ${savedUserInfo.email}`;
}

이 부분에서 에러가 발생한 것인데, innerText 는 위의 saveUserInfo에서는 잘 작동되던 메소드였다…
stackoveflow에서 검색해보니 렌더링이 되기 전에 요소를 참조하지 못해서 null참조 오류가 나오는 거라고..
해결 방안 첫번째는 순서를 변경하는것. 이미 최 하단에 있기때문에 결과에 변동이 있을것같지 않다.
두번째 방법은 이벤트 후킹. 아래는 본 프로젝트와 관련없는 단순 예시이다.

window.onload = function() {
    what();
    function what(){
    document.getElementById('hello').innerHTML = 'hi';
    };
}

위의 예시를 참고하여 수정해보았다.

window.onload = function () {
  if (savedUserInfo.name && savedUserInfo.email) {
    console.log(savedUserInfo);

    document.getElementById(
      'userInfo'
    ).innerText = `이름: ${savedUserInfo.name}, 이메일: ${savedUserInfo.email}`;
  }
};

추가로 동기분들이 해결한 방법중에 하나는 html문서 head에 있는 script를 body로 옮겨서 해결하셨다고 한다. (본문에는 body만 있고 head는 없지만 head 영역에 script 링크가 걸려있었다)
스크립트 링크를 옮기지 않고 해결할 수 있는 다른 방안으로는 아래의 코드로 수정하면 된다.

document.addEventListener('DOMContentLoaded', () => {
  if (savedUserInfo.name && savedUserInfo.email) {
    document.getElementById(
      'userInfo'
    ).innerText = `이름: ${savedUserInfo.name}, 이메일: ${savedUserInfo.email}`;
  }
});

여기서 DOMContentLoaded는 브라우저가 HTML을 전부 읽고 DOM 트리를 완성하는 즉시 발생한다. dㅣ미지 파일이나 스타일시트 등의 기타 자월은 기다리지 않는다.
window.onload는 스타일, 이미지 등의 리소스들이 모두 로드되었을 때 실행된다.
사용에 맞게 골라 쓰면 될 것 같다
DOMContentLoaded 와 window.onload 차이 || javascript.info

최종 완성 된 .js 파일

// 사용자 정보 저장 함수
function saveUserInfo() {
  const name = document.getElementById('nameInput').value;
  const email = document.getElementById('emailInput').value;

  const userInfo = {
    name: name,
    email: email,
  };

  localStorage.setItem('user', JSON.stringify(userInfo));

  document.getElementById(
    'userInfo'
  ).innerText = `이름: ${name}, 이메일: ${email}`;
}

const savedUserInfo = JSON.parse(localStorage.getItem('user'));

// 페이지 로드 시 저장된 사용자 정보가 있으면 화면에 표시
window.onload = function () {
  if (savedUserInfo.name && savedUserInfo.email) {
    console.log(savedUserInfo);

    document.getElementById(
      'userInfo'
    ).innerText = `이름: ${savedUserInfo.name}, 이메일: ${savedUserInfo.email}`;
  }
};

개인 PC라면 상관없지만 공용PC라면 개발자 도구 Application/Local Storage 에서 저장한 사용자 정보를 별도로 삭제해야 한다. (프로젝트 상 삭제하거나 초기화 하는 기능은 개발하지 않았다)

코드 및 미리보기는 다음에서 확인 해 볼 수 있다.

두번째 과제 - 사용자정보 입력 2

주제 : map() 메서드와 filter()메서드를 사용해 사용자 정보를 관리할 수 있다.

기본 요구 사항

  1. 주어진 ‘users’ 배열에서 나이가 25 이상 35 미만인 사용자를 필터링하여 새로운 배열을 생성해야합니다.
  2. 필터링된 사용자 중에서 이메일 주소가 ‘gmail.com’ 도메인을 사용하는 사용자만을 추출하여 새로운 배열을 생성해야합니다.
  3. ‘renderUserData’함수 내부에서는 각 사용자의 정보를 HTML 요소로 구성하여 화면에 표시합니다.

⠀html 문서

<div id="userData"></div>
<script src="./script.js"></script>

javascript

const users = [
  { name: 'John', age: 30, email: 'john@example.com' },
  { name: 'Alice', age: 25, email: 'alice@gmail.com' },
  { name: 'Bob', age: 35, email: 'bob@gmail.com' },
  { name: 'Emma', age: 28, email: 'emma@example.com' },
  { name: 'Steve', age: 32, email: 'steve@gmail.com' },
];

// 25세 이상 35세 미만인 사용자만을 필터링하여 새로운 배열 생성

// 필터링된 사용자 중에서 이메일 주소가 gmail.com 도메인을 사용하는 사용자만을 추출하여 새로운 배열 생성

// 결과를 화면에 그리는 함수
function renderUserData(userData) {
  const userDataDiv = document.getElementById('userData');

  // innerHTML을 사용해 결과를 화면에 그려보세요
}

renderUserData(gmailUsers); // 사용자 데이터를 그리는 함수 실행

25세 이상 35세 미만인 사용자만을 필터링하여 새로운 배열 생성

function range(age) {
  return age < 35 && 24 < age;
}
const result = users.filter(range(users.age));

첫 시도는 실행되지 않았다.
Uncaught TypeError: boolean false is not a function at Array.filter () 를 뱉으며
배열에는 아무것도 담지 못함.. 에러문 확인해보니 함수지만(?) 함수가 아니라나….ㅠ
filter 내 함수에서 인자를 받는게 아닌 ture / false 값만 인식 해야하므로 range 함수 자체에서 모든걸 해결해야 했다.

두번째 도전은 성공

function range(users) {
  if (users.age < 35 && users.age > 24) {
    return true;
  } else {
    return false;
  }
}
const result = users.filter(range);

console.log(result)를 찍어보면 age가 35세인 Bob을 제외한 4명이 생성된 배열에 잘 배치되어 있었다.

궁금해서 다른 방법이 있는지 조금 더 찾아보니 아래와 같은 코드도 있었다.
stackoverslow에서 찾은 코드는 다음과 같다.

let its = (prop) => (x) => x[prop];
let inRange = (rng) => (x) => rng.min < x && x < rng.max;
Function.prototype.is = function (p) {
  return (x) => p(this(x));
};
const range = { min: 24, max: 35 };

const result = users.filter(its('age').is(inRange(range)));
console.log(result);

아직 배우지 않은 람다식인가? 변수를 정의하는 모습이 매우 간결해 보이고 가독성이 좋다.
하지만 아직 이해할 수 있는 문법이 아니기에.. 기록으로만 남겨두려 한다.
참조 문서는 여기에서 볼 수 있다.

필터링된 사용자 중에서 이메일 주소가 gmail.com 도메인을 사용하는 사용자만을 추출하여 새로운 배열 생성

// 메일 주소 도메인이 gmail.com 인 사용자
function gmailUser(ageUsers) {
  const mail = ageUsers.email;

  const domain = mail.slice(-9);
  if (domain === 'gmail.com') {
    return true;
  } else {
    return false;
  }
}
const gmailUsers = ageUsers.filter(gmailUser);

javascript 문자열에서 gmail.com으로 끝나는 단어만 자르기 위해 str.slice()를 사용하였다. 뒤에서부터 자르기 위해 -9를 인수로 사용하였다.

결과를 화면에 그리는 함수

function renderUserData(userData) {
  const userDataDiv = document.getElementById('userData');
  console.log(userData);
  userData.map(() => {
    userDataDiv.innerHTML = `
    <span> 이름 : ${userData.name}</span>
    <span> 나이 : ${userData.age}</span>
    <span> 메일 : ${userData.email}</span>
    `;
  });
}

첫 시도 실패.. 화면에 그려지기는 하나 ${userData.name} 값이 undefined으로 출력된다.
console.log(userData)로는 배열이 잘 찍히는 것으로 보아 리터럴에서 접근을 잘못 입력한 듯하다.

이것 저것 시도해보니 화살표 함수에 (user)값을 받아서 리터럴에서도 user.name을 전달하니 잘 출력되는것을 확인했다.

그리고, 한명만 출력되어서 map을 innetHTML 안으로 배치했더니 2명이 모두 잘 출력되는 것을 볼 수 있었다.

최종 .js 파일

const users = [
  { name: 'John', age: 30, email: 'john@example.com' },
  { name: 'Alice', age: 25, email: 'alice@gmail.com' },
  { name: 'Bob', age: 35, email: 'bob@gmail.com' },
  { name: 'Emma', age: 28, email: 'emma@example.com' },
  { name: 'Steve', age: 32, email: 'steve@gmail.com' },
];

// filter : 25 세 이상 35세 미만
function range(users) {
  if (25 <= users.age && users.age < 35) {
    return true;
  } else {
    return false;
  }
}
const ageUsers = users.filter(range);

// 메일 주소 도메인이 gmail.com 인 사용자
function gmailUser(ageUsers) {
  const mail = ageUsers.email;

  const domain = mail.slice(-9);
  if (domain === 'gmail.com') {
    return true;
  } else {
    return false;
  }
}
const gmailUsers = ageUsers.filter(gmailUser);

// 결과를 화면에 그리는 함수
function renderUserData(userData) {
  const userDataDiv = document.getElementById('userData');
  userDataDiv.innerHTML = userData.map(
    (user) =>
      `
    <div class="user">
      <p><strong> 이름 : </strong> ${user.name}</p>
      <p><strong> 나이 : </strong> ${user.age}</p>
      <p><strong> 메일 : </strong> ${user.email}</p>   
    </div>
    `
  );
}
// 사용자 데이터를 그리는 함수 실행
renderUserData(gmailUsers);

원래 공부하는 스타일은 일단 시작하면서 막히는 부분이 있으면 잠깐 찾아보다가 적용하고 완료하고나면
작업한 내용중 인상 깊었던 것을 정리하는 식으로 했었는데, 작업 시간이 길어지다 보면 기억이 잘 안 날때도 있고 아예 생각이 안나는 경우도 많았다.

그래서 작업할 때 아예 에디터를 켜놓고 바로바로 적어서 정리해 가면서 하니 내가 어느부분에서 막혔는지, 어떤방법을 써서 오류를 잡았는지가 잘 보여서 더 좋은 것 같다. 다만 시간이 조금 더 걸린다는 것..

좀 더 익숙해지고 검색이 덜 필요할 쯤에는 조금 더 나아지지 않을까..

1차 미션과제는 오전중으로 금방 끝났는데 2차 미션과제에서 시간이 지체된 것 같다.
거의 두세배는 더 걸린것 같다… ㅠ

728x90