깃허브
약 9개월 전에 바닐라 자바스크립트로 만든 로또 추첨기 를 리액트로 다시 제작해봤습니다.
손보는 김에 예전엔 모바일 기기에선 공을 세로로 일렬로 표시했으나, 이젠 3열로 표시하게 해뒀습니다.
버리는 공간이 훨씬 적어진 느낌이라 마음에 드네요.
바닐라로 짤 땐 html에 .ball이란 div를 만들고, #button을 클릭하면 document.querySelectorAll(".ball")로 DOM에 접근해 내용을 바꾸는 방식으로 작업하는데, 리액트로 짜니 컴포넌트를 만들고, 버튼을 클릭하면 컴포넌트의 상태를 업데이트하는 전혀 다른 방식으로 진행해야 해 난항을 겪었네요.
처음엔 바닐라만큼 직관적이진 않다고 느꼈으나, 한 엘리먼트에 여러 곳에서 접근하다 코드가 꼬이는 등의 불상사는 일어날 일이 없어 보이니 단순한 접근 방식의 차이일 뿐이지 직관성은 뛰어날 수도 있겠다 싶습니다.
import React from " react " ;
import ReactDOM from " react-dom " ;
import " ./index.css " ;
const numbers = [ ... Array ( 45 ) . keys ()] ;
class LotteryBox extends React . Component {
state = { number : [ 0 , 0 , 0 , 0 , 0 , 0 , 0 ] };
randomize = () => {
if ( ! this . state . effect ) {
const numberCopy = numbers . map ( ( x ) => x ) ;
const arr = [] ;
for ( let i = 0 ; i <= 7 ; i ++ ) {
const random = Math . floor (
Math . random () * ( numberCopy . length - 1 )
) ;
arr . push ( numberCopy [ random ] + 1 ) ;
numberCopy . splice ( random , 1 ) ;
}
this . setState ( { number : arr , effect : true } ) ;
setTimeout ( () => {
this . setState ( { effect : false } ) ;
}, 8000 ) ;
}
};
render () {
return (
< React.Fragment >
< h1 id = " title " > Lotto </ h1 >
< div id = " numbers " >
< LotteryItem
index = " 0 "
color = " blue "
number = { this . state . number [ 0 ] }
decrypting = { this . state . effect }
/>
< LotteryItem
index = " 1 "
color = " blue "
number = { this . state . number [ 1 ] }
decrypting = { this . state . effect }
/>
< LotteryItem
index = " 2 "
color = " blue "
number = { this . state . number [ 2 ] }
decrypting = { this . state . effect }
/>
< LotteryItem
index = " 3 "
color = " red "
number = { this . state . number [ 3 ] }
decrypting = { this . state . effect }
/>
< LotteryItem
index = " 4 "
color = " red "
number = { this . state . number [ 4 ] }
decrypting = { this . state . effect }
/>
< LotteryItem
index = " 5 "
color = " grey "
number = { this . state . number [ 5 ] }
decrypting = { this . state . effect }
/>
< div className = " plus " > + </ div >
< LotteryItem
index = " 6 "
color = " bonus "
number = { this . state . number [ 6 ] }
decrypting = { this . state . effect }
/>
</ div >
< div >
< LotteryButton
decrypting = { this . state . effect }
run = { this . randomize }
/>
</ div >
</ React.Fragment >
) ;
}
}
class LotteryButton extends React . Component {
render () {
return (
< button
id = " btn "
className = { this . props . decrypting && " hide " }
onClick = { this . props . run }
>
추첨!
</ button >
) ;
}
}
class LotteryItem extends React . Component {
constructor ( props ) {
super ( props ) ;
this . state = {
number : " ? " ,
decryptingDone : "" ,
};
}
decryptEffect () {
this . setState ( { decryptingDone : "" } ) ;
this . timer = setInterval ( () => {
this . randomNumber () ;
}, 10 ) ;
setTimeout ( () => {
this . setState ( {
decryptingDone : " done " ,
number : this . props . number ,
} ) ;
clearTimeout ( this . timer ) ;
}, 1000 * + this . props . index + 1000 ) ;
}
randomNumber () {
this . setState ( { number : Math . round ( Math . random () * 44 ) + 1 } ) ;
}
componentDidUpdate ( nextProps ) {
const { decrypting } = this . props ;
if ( nextProps . decrypting !== decrypting ) {
if ( decrypting ) {
this . decryptEffect () ;
}
}
}
render () {
return (
< div
className = { ` ball ${ this . props . color } ${ this . state . decryptingDone } ` }
>
{ this . state . number }
</ div >
) ;
}
}
ReactDOM . render ( < LotteryBox /> , document . getElementById ( " root " )) ;
아직 React 초보라, LotteryItem에 index를 일일이 넣어주는 점이며, LotteryBox의 number란 array의 아이템을 LotteryItem에 하나씩 전달해주는 점이 굉장히 우아하지 못한 것 같은데, 첫술에 배를 불리려는 건 과욕이겠지요. 😂
ⓒ 2020. Marshall K All rights reserved