[React] 코딩 타자 연습 사이트 만들기 (14) - 타자연습 로그 남기기 + 로컬 스토리지 관리

Maple·2024년 10월 29일
0

코드보기 : https://github.com/maplesyrup0423/DevTyper

타자연습 로그 남기기

로그 남기는 방식

DB를 이용하는 방법은 기존 다른 프로젝트에서 많이 사용해 봤기에 이번에는 로컬 스토리지를 사용하는 방법으로 진행하기로 했다.

1. 로컬 스토리지 사용

로컬 스토리지는 사용자의 브라우저에 데이터를 저장하는 방식입니다.

장점

  • 간단함: 서버 설정이나 데이터베이스 없이 빠르게 구현할 수 있어 간단한 개인 프로젝트에 적합합니다.
  • 속도: 로컬 스토리지에 저장된 데이터는 브라우저 내에서 바로 접근 가능하므로 속도가 빠릅니다.
    오프라인 가능: 네트워크 연결 없이도 데이터를 로드하고 관리할 수 있습니다.

단점

  • 브라우저마다 독립적: 로컬 스토리지는 브라우저마다 따로 저장되므로 사용자가 다른 기기나 브라우저를 사용하면 기록을 볼 수 없습니다.
  • 용량 제한: 로컬 스토리지에는 보통 5~10MB의 용량 제한이 있어, 데이터를 무제한으로 저장할 수 없습니다.
  • 보안 약점: 로컬 스토리지에 저장된 데이터는 브라우저 개발자 도구로 쉽게 접근할 수 있어 민감한 정보는 적합하지 않습니다.

2. 서버와 데이터베이스 사용

서버에 데이터를 저장하는 방식은 데이터베이스를 통해 서버에 정보를 저장하는 방법입니다.

장점

  • 기기 간 데이터 동기화: 서버에 저장된 데이터는 사용자가 어느 기기에서나 접근할 수 있어 여러 브라우저나 기기에서 같은 기록을 공유할 수 있습니다.
  • 확장성: 데이터를 더 많이 저장하거나 복잡한 쿼리를 사용할 수 있어 대규모 프로젝트나 향후 기능 확장에 유리합니다.
  • 보안 강화: 서버는 더 높은 수준의 보안을 적용할 수 있으므로 민감한 정보 저장에도 적합합니다.

단점

  • 설정의 복잡성: 서버와 데이터베이스 설정 및 유지 관리는 초기 설정이 더 복잡합니다.
  • 네트워크 의존성: 사용자가 데이터를 불러오기 위해 항상 네트워크 연결이 필요합니다.
  • 비용: 클라우드 서버와 데이터베이스를 사용할 경우 비용이 발생할 수 있습니다.

추천:

  • 간단한 개인 프로젝트나 학습 목적이라면 로컬 스토리지를 활용하는 것이 더 빠르고 쉬운 선택이 될 수 있습니다.
  • 다수의 기기에서 접근해야 하거나 향후 확장 가능성을 고려한 서비스라면 서버와 데이터베이스를 사용하는 것이 더 적합합니다.

1. 기록 저장 함수 추가하기

const saveTypingRecord = (time, accuracy, wpm) => {
  const completedAt = new Date().toLocaleString(); // 완료된 시간
  const record = { completedAt, time, accuracy, wpm };

  // 기존 기록을 가져와 배열로 저장하거나 빈 배열로 초기화
  const storedRecords = JSON.parse(localStorage.getItem("typingRecords")) || [];
  storedRecords.push(record);

  // 로컬 스토리지에 갱신된 기록 저장
  localStorage.setItem("typingRecords", JSON.stringify(storedRecords));
};

2. 타이핑 완료 시 기록 저장 호출


// 타이핑 완료 및 기록 저장
useEffect(() => {
  const cleanedCodeToType = codeToType.replace(/\s+/g, " ").trim();

  if (userInput.length >= cleanedCodeToType.length && userInput.length > 0) {
    const endTime = new Date().getTime();
    setIsFinished(true);

    const timeTaken = (endTime - startTime) / 1000; // 초 단위 소요 시간
    const correctChars = userInput
      .split("")
      .filter((char, index) => char === cleanedCodeToType[index]).length;

    // 정확도 계산
    const accuracy = ((correctChars / cleanedCodeToType.length) * 100).toFixed(2);
    setAccuracy(accuracy);

    // 총 입력한 글자 수 기준 WPM 계산
    const wpm = (userInput.length / 5 / (timeTaken / 60)).toFixed(2); // 5글자 = 1 단어 기준
    setWpm(wpm);

    // 기록을 로컬 스토리지에 저장
    saveTypingRecord(timeTaken.toFixed(1), accuracy, wpm);
  }
}, [userInput, codeToType, startTime]);

3. 상태 추가

const [typingRecords, setTypingRecords] = useState([]);

4. 기록 불러오기

  //컴포넌트가 마운트될 때 로컬 스토리지에서 기록을 불러옴
  useEffect(() => {
    fetchJSFilesFromGithub(); // 컴포넌트가 처음 렌더링될 때 .js 파일을 가져옵니다.
    const storedRecords =
      JSON.parse(localStorage.getItem("typingRecords")) || [];
    setTypingRecords(storedRecords);
  }, []);
useEffect(() => {
    if (isFinished) {
      saveTypingRecord(); // 타자 연습 완료 시 기록 저장
      const storedRecords =
        JSON.parse(localStorage.getItem("typingRecords")) || [];
      setTypingRecords(storedRecords); // 갱신된 기록 설정
    }
  }, [isFinished]);

시작할때와 타자연습 완료시마다 불러올 수 있게 했다.

5. 기록 표시

      {/* 저장된 기록 표시 */}
      <div className="typing-records">
        <h3>타자 연습 기록</h3>
        {typingRecords.length > 0 ? (
          <div>
            {typingRecords.map((record, index) => (
              <div key={index} className="typingRecords">
                <p>완료 시간: {record.completedAt}</p>
                <span>소요 시간: {record.time}</span>
                &nbsp;&nbsp;&nbsp;||&nbsp;&nbsp;&nbsp;
                <span>정확도: {record.accuracy}%</span>
                &nbsp;&nbsp;&nbsp;||&nbsp;&nbsp;&nbsp;
                <span>속도: {record.wpm} WPM</span>
              </div>
            ))}
          </div>
        ) : (
          <p>기록이 없습니다.</p>
        )}
      </div>

.typing-records {
  width: 600px;
  height: 500px;
  overflow: auto;
  margin: auto;
  margin-top: 20px;
  border: 2px solid #ffcd19;
  border-radius: 10px;
  padding: 20px;
}
/* 스크롤바 스타일 */
.typing-records::-webkit-scrollbar {
  width: 10px; /* 스크롤바의 너비 */
}

.typing-records::-webkit-scrollbar-track {
  background: none; /* 스크롤바 트랙 색상 */
}

.typing-records::-webkit-scrollbar-thumb {
  background: #ddb72d; /* 스크롤바 색상 */
  border-radius: 10px; /* 모서리 둥글게 */
}

.typing-records::-webkit-scrollbar-thumb:hover {
  background: #8d782d; /* 스크롤바 호버 시 색상 */
}

.typing-records h3 {
  text-align: center;
}

.typingRecords {
  padding: 10px;
  border: 2px solid #ffcd19;
  margin-top: 5px;
}

6. 결과 확인

번외: 로컬 스토리지 관리

개발자 도구 -> Application ->Local Storage 에서 확인가능

typingRecords라는 키를 찾아 해당 값을 확인시 저장된 타자 연습 기록을 JSON 형식으로 볼 수 있다.
Delete 키로 삭제하거나 localStorage.clear()로 초기화 가능

특정 값만 지우고싶은경우

Console 탭 에서

// 로컬 스토리지에서 typingRecords 불러오기
const storedRecords = JSON.parse(localStorage.getItem("typingRecords")) || [];

// 3번째 항목 삭제하기 (인덱스는 2)
if (storedRecords.length > 2) {
  storedRecords.splice(2, 1); // 3번째 항목 삭제
}

// 수정된 배열을 로컬 스토리지에 다시 저장
localStorage.setItem("typingRecords", JSON.stringify(storedRecords));

특정 항목을 선택해 지울 수 있다.

0개의 댓글