일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- nodeJS
- 리액트기초
- node
- NoSQL
- 리액트
- 시퀄라이즈
- sequelize
- npm명령어
- 제로초예제
- 시퀄라이즈공부
- express-generator
- 리액트컴포넌트
- 리액트스타디
- nodejs교과서
- NPM
- sementicversion
- 클래스컴포넌트
- mongoose
- React Component
- mongo
- MongoDB
- React
- component
- Today
- Total
개발노트
12. componentDidUpdate , setInterval 본문
1~45까지 숫자만들어서 섞어서 7개 반환하는 함수
function getPickNumbers(){
console.log('pickNum START');
const numArray = Array(45).fill().map( (v,i) => i + 1 ); // 1~45정수 배열 만듬.
const shuffle = [];
while( numArray.length>0 ){ //1~45를 랜덤하게 섞기 위해서
shuffle.push( numArray.splice( Math.floor( Math.random() * numArray.length ) ,1)[0] );
// (1~10랜덤) * 45 한다음 45,44 랭스 바뀌게 이렇게 그숫자 하나씩 제거 (곱하는건왜하는건지? 알고리즘인데,)
//그숫자 push
}
const bonusNumber = shuffle[shuffle.length -1]; //섞어서 마지막은 보너스번호로 픽-
const rltNumbers = shuffle.slice(0,6).sort( (p,c)=>p-c ); //섞었으니앞에서부터 그냥 여섯개뽑고, 쏘팅
return[...rltNumbers, bonusNumber]; // 여섯개, 보너스1 해서 반환.
};
jsx
balls (array) 갯수만큼 무조건 화면에 보여주게
//Lotto.jsx
<>
<h1>당첨숫자</h1>
<ul id="rlt_box">
{ balls.map( ( v )=>( <Ball key={v} num={v} /> ) )}
{ bonus && <Ball num={bonus} /> }
</ul>
{ rePick && <button onClick={ rePick ? this.onClickRePick :()=>{} } >한번더</button> }
</>
//Ball.jsx
return(
<li className='ball' style={{ background: `${bg}` }}>{ num }</li>
)
상태값 변경 작업 componentDidMount
번호 7개를 다 뽑아둔 다음, pickNumbers (array)
setTimeout 으로 (1+0), (1+1), (1+2)... 초 마다
balls Array에다 1개 1개 추가해줌. balls(array)가 화면에 보이는 볼들,
componentDidMount(){
const {pickNumbers}=this.state;
for( let i=0; i<pickNumbers.length-1; i++){
setTimeout( ()=>{
this.setState( (prevState)=>{
return{
balls: [ ...prevState.balls, pickNumbers[i] ], ////
}
})
} , (i+1)*100 ) ;
}
setTimeout(
()=>{
this.setState({
bonus: pickNumbers[6],
rePick:true
})
}
,700
)
}
push해서 하나씩 더 추가하는것 이기 때문에 prevState사용.
※
부모컴포넌트가 자식컴포넌트를 없앨때는 setTimeout을 클리어 해줘야 된다.
메모리문제, 해당컴포넌트가 없어졌는데 setState(또는setTimeout) 하면 안되기 때문에
이런 논리적이지 않은 코드로인해 의도치않은 에러가 생길수 있음
setTimeout을 썻으면 clear해줘야함
갯수만큼 클리어 componentWillUnMount
timer = []; ///
componentDidMount(){
const {pickNumbers}=this.state;
for( let i=0; i<pickNumbers.length-1; i++){
this.timer[i] = setTimeout( ()=>{ ///
this.setState( (prevState)=>{
return{
balls: [ ...prevState.balls, pickNumbers[i] ],
}
})
} , (i+1)*100 ) ;
}
}
componentWillUnmount(){
this.timer.forEach( (v)=>{ clearTimeout(v) }); ///
}
pickNumbers의 length만큼 반복시켜 발생시킨 setTimeout을 clear하기 위해,
새 배열을 만들어 발생시킬때마다 담아준다
unmount에 forEach반복문으로 timer갯수만큼 clear시켜준다
setTimeout발생후, 바로 삭제(부모컴포넌트가자식컴포넌트를삭제)될수도 있으니 갯수만큼 삭제
다시실행 componentDidUpdate
onClickRePick = () =>{
//초기화
this.setState({
pickNumbers: getPickNumbers(), // 6
balls:[],
bonus: null,
rePick: false,
});
//timer
this.timer=[];
}
(1)초기화 그래고 (2)componentDidMount코드로 똑같이 실행 시키면 된다.
componentDidUpdate를 사용하면 (초기값으로)상태값을 바꾼거를
어떤어떤게 바꼈는지 여기서 판단할 수 있다.
바뀌기전 state는 prevState,
바뀐후 state는 this.State
prevProps는 부모한테서받은 props이 바뀔수도 있어서
클릭했을때 balls값들을 비워주니까
만약 balls이 비었으면 로또를 다시 시작해주라고 할수 있다.
componentDidUpdate( prevProps, prevState){
if( this.state.balls.length === 0 ){
this.lottoStarting ();
}
}
조건을 꼭 써야 되는데, DidUpdate 이벤트가 setState가 일어날때마다 발생하기 때문에,
onClickRePick버튼눌렀을때만 발생할 수 있도록 ===0일때로 걸어준것.
React.memo컴포넌트
Ball.jsx에 memo컴포넌트를 넣지않을경우 이렇게 자식들한테 렌더링이 발생
메모넣을경우
//Ball.jsx
import React from 'react';
const Ball = React.memo( ({ num }) =>{
let bg;
if( num < 10 ){
console.log('1');
bg = '#ffd700';
}else if( num <= 20 ){
bg = '#ff972c';
}else if( num <= 30 ){
bg = '#8bc34a';
}else if( num <= 40 ){
bg = '#009688';
}else{
bg = '#fb7fd5';
}
return(
<li className='ball' style={{ background: `${bg}` }}>{ num }</li>
)
})
export default Ball;
//Lotto.jsx
import React, { Component } from 'react';
import Ball from './Ball';
function getPickNumbers(){
console.log('pickNum START');
const numArray = Array(45).fill().map( (v,i) => i + 1 );
const shuffle = [];
while( numArray.length>0 ){
shuffle.push( numArray.splice( Math.floor( Math.random() * numArray.length ) ,1)[0] );
}
const bonusNumber = shuffle[shuffle.length -1];
const rltNumbers = shuffle.slice(0,6).sort( (p,c)=>p-c );
return[...rltNumbers, bonusNumber];
};
class Lotto extends Component {
state = {
pickNumbers: getPickNumbers(), // 6
balls:[],
bonus: null,
rePick: false,
}
timer = [];
lottoStarting = ()=>{
const {pickNumbers}=this.state;
for( let i=0; i<pickNumbers.length-1; i++){
this.timer[i] = setTimeout( ()=>{ ///
this.setState( (prevState)=>{
return{
balls: [ ...prevState.balls, pickNumbers[i] ],
}
})
} , (i+1)*100 ) ;
}
this.timer[6] = setTimeout( //얘도setImterval이니까 clear해주기위해담는다.
()=>{
this.setState({
bonus: pickNumbers[6],
rePick:true
})
}
,700
)
}
componentDidMount(){
this.lottoStarting ();
}
componentWillUnmount(){
this.timer.forEach( (v)=>{ clearTimeout(v) });
}
onClickRePick = () =>{
//초기화
this.setState({
pickNumbers: getPickNumbers(), // 6
balls:[],
bonus: null,
rePick: false,
});
//timer
this.timer=[];
}
componentDidUpdate( prevProps, prevState){
if( this.state.balls.length === 0 ){
this.lottoStarting ();
}
}
render(){
const{ balls, bonus , rePick } = this.state;
return(
<>
<h1>당첨숫자</h1>
<ul id="rlt_box">
{ balls.map( ( v )=>( <Ball key={v} num={v} /> ) )}
{ bonus && <Ball num={bonus} /> }
</ul>
{ rePick && <button onClick={ rePick ? this.onClickRePick :()=>{} } >한번더</button> }
</>
)
}
}
export default Lotto;
<html lang="ko">
<head>
<meta charset="utf-8">
<title>game</title>
</head>
<style>
ul{ width:100%; float:left;}
.ball {
list-style: none;
float: left;
border: 1px solid white;
border-radius: 20px;
width: 40px;
height: 40px;
color: #fff;
FONT-WEIGHT: 700;
line-height: 40px;
font-size: 20px;
text-align: center;
margin-right: 20px;
}
</style>
<body>
<div id="root"></div>
<script src="./dist/app.js">
</script>
</body>
</html>
'React > basic' 카테고리의 다른 글
13. useReducer (0) | 2020.07.28 |
---|---|
12. hooks / useEffect , useMemo (0) | 2020.07.28 |
11 (2)hooks / useEffect (0) | 2020.07.26 |
11. react life cycle (0) | 2020.07.26 |
10. (4)jsx 에서 for, if (0) | 2020.07.26 |