TIL_2023_10_11

이종현·2023년 10월 11일
0

Today_I_Learned

목록 보기
102/145
post-thumbnail

Today 요약

  1. 주사위 게임 프로젝트 기능 구현
  2. 컴포넌트 필터링 하기
  3. 드롭다운 컴포넌트 구현하기

1. What I did?

1.1 주사위 게임 프로젝트 기능 구현

오늘부터 이제 주사위 게임의 기능을 구현하기 시작했다. 일단 처음으로 구현할 기능은 주사위를 랜덤으로 돌리고 랜덤으로 돌린 주사위의 점수를 current score에 반영한다. 랜덤으로 돌릴 때마다 주사위 이미지도 같이 변경되어야 하고, 1 ~ 2의 주사위 숫자가 나오면 점수가 초기화되고 3 ~ 6의 숫자가 나오면 누적된다. 오늘은 시간상 이 기능만 구현해보았다.

const rollDiceBtn = document.querySelector('.roll-dice')
const diceImgElem = document.querySelector('.dice-img')
const diceImgWrap = document.querySelector('.dice-img--wrap')
const player1CurrentScore = document.querySelector('.player1 .current--score')

let currentScore = 0
let accumulateScore = 0
let totalScore = 0

console.log(diceImgElem.src)

rollDiceBtn.addEventListener('click', () => {
  currentScore = Math.floor(Math.random() * 6 + 1)

  diceImgElem.src = `http://127.0.0.1:8080/assets/dice0${currentScore}.png`

  diceImgElem.classList.add('active')

  if (currentScore < 3) {
    currentScore = 0
    totalScore = 0
    player1CurrentScore.innerHTML = 0
    accumulateScore = 0
  } else if (currentScore >= 3) {
    accumulateScore += currentScore
    totalScore = totalScore + currentScore

    player1CurrentScore.innerHTML = accumulateScore
  }

  console.log('currentScore', currentScore)
  console.log('accumulateScore', accumulateScore)
  console.log('totalScore', totalScore)
})

필요한 경우마다 console을 찍어보면서 하나하나 순차적으로 시도해서 해결했다.

일단 필요한 버튼이나 DOM요소를 가지고 와서 버튼을 클릭했을 때 랜덤한 숫자를 받아오면서 이미지도 같이 동적으로 변경될 수 있도록 구현했고, 요구 사항에 따라 주사위 숫자가 1 ~ 2일때는 초기화하고 3 ~ 6일 때는 누적할 수 있도록 구현했다.

2. What I Learned?

2.1 컴포넌트 필터링 하기

컴포넌트를 필터링 하는 부분은 어느 컴포넌트에서 컴포넌트 리스트의 정보에 대한 배열을 가지고 있는지에 따라 배열을 가지고 있는 컴포넌트에서 필터링 로직을 구현할지 아니면 배열에 대한 데이터를 prop으로 전달해서 하위 컴포넌트에서 처리할지는 개발자가 하기 나름이다. 하지만 결국 props drilling이 너무 깊어져버리면 계속 하위 컴포넌트로 prop을 내리기보다는 context로 가장 상위 컴포넌트에서 처리해서 사용하는 것이 좋을 것 같다는 생각이다. 아직 해당 강의가 거기까지는 진행되지 않았기 때문에 prop으로 전달해서 사용하는 부분을 계속 반복학습 하는 것 같다는 생각이 든다.

function App() {
  const [expenses, setExpenses] = useState([
    {
      id: 'e1',
      title: '수건',
      amount: 12.33,
      date: new Date(2022, 3, 14)
    }
    //		... 생략
  ])

  const getPaymentFormData = (data) => {
    setExpenses([
      {
        id: Math.random().toString(),
        title: data.name,
        amount: data.price,
        date: new Date(data.today)
      }
    ])
  }

  return (
    <>
      <PaymentForm getPaymentFormData={getPaymentFormData} />
      <Expenses items={expenses} />
    </>
  )
}

export default App
const Expenses = (props) => {
  const [filteredYear, setFilteredYear] = useState('2023')

  const filterChangeHandler = (selectedYear) => {
    setFilteredYear(selectedYear)
  }

  return (
    <Card className="expenses">
      <ExpensesFilter
        selected={filteredYear}
        onChangeFilter={filterChangeHandler}
      />
      {props.items.map((item) => (
        <ExpenseItem title={item.title} amount={item.amount} date={item.date} />
      ))}
    </Card>
  )
}

export default Expenses

App 에서 expenses 배열을 가지고 있고 그걸 Expenses 컴포넌트에 prop으로 전달한다.

Expenses 컴포넌트에서 ExpenseFilter 컴포넌트에서 input의 value로 값을 받아오고 그 값을 업데이트해서 Expenses 컴포넌트에서 가지고 있고 그 값을 활용해서 Expenses 컴포넌트에서 prop으로 받아온 배열을 filter해서 필터링을 구현한다.

const filteredExpenses = props.items.filter(
  (expense) => expense.amount <= Number(filteredPrice)
)

2.2 드롭다운 컴포넌트 구현하기

드롭다운 컴포넌트 구현하는 부분은 나중에 다시 한 번 내가 스스로 구현해봐야 한다. 오늘은 강의 내용을 따라가는 방식으로 구현했다.

import Dropdown from './Dropdown'

function App() {
  const options = [
    { id: 1, label: '빨강', value: 'red' },
    { id: 2, label: '녹색', value: 'green' },
    { id: 3, label: '파랑', value: 'blue' }
  ]

  return <Dropdown options={options} />
}

export default App
import React from 'react'
import { useState } from 'react'

const Dropdown = ({ options }) => {
  const [isOpen, setIsOpen] = useState(false)
  const [selectedOption, setSelectedOption] = useState(null)

  const handleClick = () => {
    setIsOpen((prevState) => !prevState)
  }

  const handleSelect = (option) => {
    setSelectedOption(option)
    setIsOpen(false)
  }

  console.log(selectedOption)

  const renderedOptions = [...options].map((option) => {
    return (
      <div key={option.id} onClick={() => handleSelect(option)}>
        {option.label}
      </div>
    )
  })

  return (
    <>
      <div onClick={handleClick}>
        {!selectedOption ? '선택하기' : selectedOption.label}
      </div>
      {isOpen && <>{renderedOptions}</>}
    </>
  )
}

export default Dropdown

중요한 건 드롭다운의 동작을 아주 자세하게 설명하고 나눠본다는 것이다. 그리고 상태로 처리할 부분과 이벤트로 처리할 부분을 나눠서 생각해본다.

  1. 드롭다운 클릭 - 이벤트
  2. 옵션들이 나타남 - 상태
  3. 하나의 옵션을 클릭함 - 이벤트
  4. 옵션들이 사라짐 - 상태
  5. 클릭한 옵션이 박스에 표시됨 - 상태

그리고 비슷한 것들끼리 묶어서 처리한다. (isOpen, selectedOption)(handleSelect, handleClick)


profile
데이터리터러시를 중요하게 생각하는 프론트엔드 개발자

0개의 댓글