반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
Tags
- Wecode
- 자바스크립트
- JavaScript
- CSS
- Vue.js
- 자료구조
- event
- react
- mapGetters
- Vue transition
- express
- 댓글달기
- Vue
- 쉬운설명
- ES6
- vuex
- 리액트
- storybook
- jsx
- HOC
- nodejs
- v-html
- TypeScript
- input
- State
- MySQL
- App.vue
- scss
- sass
- webpack
Archives
- Today
- Total
익명의 개발노트
리액트 Hook 본문
반응형
Hook 간다는 의미인가?
리액트 안에서 기본적으로 사용했던 클래스, state가 없을때 사용했던 함수형으로 했었는데.
리액트 훅은 함수형에 ref와 state를 사용할 수 있게 해준 거다.
실제로 써보면 클래스형 컴포넌트보다 훨씬 간결해짐을 볼 수 있다.
클래스형
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class GuGudan extends React.Component {
constructor(props){
super(props);
this.state={ //수동으로 바꿀값들만 여기다가 넣는다.
first: Math.ceil(Math.random() *9),
second: Math.ceil(Math.random() *9),
value : '',
result : '',
};
} //end constructor
onSubmit =(e) => {
e.preventDefault();
if(parseInt(this.state.value) === this.state.first * this.state.second){
this.setState((prevState) => {
return {
result : '정답 : '+prevState.value, //이값은 과거 state값이고 나머지들은 현재값이라. 시점의 차이날 경우. setState() 안에 (prevState) => return {} 으로 값넣으면 좋다.
first: Math.ceil(Math.random() *9),
second: Math.ceil(Math.random() *9),
value : '',
}
});
this.input.focus();
}else{
this.setState((prevState) => {
return {
result: prevState.value+'땡',
value : '',
}
});
this.input.focus();
}
};
onChange = (e) =>{
this.setState({value:e.target.value});
};
render(){
// console.log("랜더링"); setState하면 랜더링되기때문에 나중에 성능최적화해야함.
return(
<React.Fragment>
<div>{this.state.first}곱하기{this.state.second}는?</div>
<form onSubmit={this.onSubmit}>
<input ref={(c) => {this.input = c;}} type="number" value={this.state.value} onChange={this.onChange}/>
<button>입력!</button>
</form>
<div>{this.state.result}</div>
</React.Fragment>
)
}
}
</script>
<script type="text/babel">
ReactDOM.render(<React.Fragment><GuGudan /></React.Fragment>, document.querySelector('#root'));
</script>
</body>
</html>
함수형 훅 사용
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
//setState 사용하지 않는 것은 함수형. 훅스 : 함수형+ref, state 사용
const GuGudan = ()=>{
const [first, setFirst] = React.useState(Math.ceil(Math.random()*9));
const [second, setSecond] = React.useState(Math.ceil(Math.random()*9));
const [value, setValue] = React.useState('');
const [result, setResult] = React.useState('');
const inputRef = React.useRef(null);
const onChangeInput = (e) =>{
setValue(e.target.value);
}
const onSubmitForm = (e) =>{
e.preventDefault();
if(parseInt(value) === first * second){
setResult('정답 : '+value);
setFirst(Math.ceil(Math.random()*9));
setSecond(Math.ceil(Math.random()*9));
setValue('');
inputRef.current.focus();
}else{
setResult('땡! 입력하신 결과는'+value);
setValue('');
inputRef.current.focus();
}
}
return(
<React.Fragment>
<div>{first}곱하기{second}는?</div>
<form onSubmit={onSubmitForm}>
<input ref={inputRef} type="number" value={value} onChange={onChangeInput}/>
<button>입력!</button>
</form>
<div>{result}</div>
</React.Fragment>
);
}
</script>
<script type="text/babel">
ReactDOM.render(<GuGudan />, document.querySelector('#root'));
</script>
</body>
</html>
왠만한건 변수로 선언해서 빼버림.
편리해보인다.
참고자료 : 제로초님 유튜브 강좌(웹게임) https://www.youtube.com/watch?v=EUQnxfZgFJU&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn&index=11
1. useEffect : 라이프싸이클을 대신해준다.
2. useMemo : 메모이즈 기능으로 값을 저장해준다.
3. useCallback : 함수를 저장해준다.
클래스 사용
const React = require('react');
const { Component } =React;
const Ball = require('./Ball');
//숫자 미리뽑기
function getWinNumbers(){
console.log('getWinNumbers');
const candidate = Array(45).fill().map((v,i) => i+1);
const shuffle =[];
while(candidate.length>0){
shuffle.push(candidate.splice(Math.floor(Math.random() * candidate.length), 1)[0]);
}
const bonusNumber = shuffle[shuffle.length-1];
const winNumbers = shuffle.slice(0,6).sort((p,c) => p-c);
return [...winNumbers, bonusNumber];
}
class Lotto extends Component{
state = {
winNumbers : getWinNumbers(), //당첨숫자
winBalls :[],
bonus : null, //보너스공
redo : false,
}
//비동기 관리할때 변수만들어서 담으면됨.
timeouts = [];
runTimeouts = () => {
const {winNumbers} = this.state;
for(let i =0; i<winNumbers.length -1; i++){
this.timeouts[i] = setTimeout(()=>{
this.setState((prevState)=>{
return {
winBalls:[...prevState.winBalls, winNumbers[i]]
};
});
}, (i+1) * 1000);
}
this.timeouts[6] = setTimeout(()=>{
this.setState({
bonus : winNumbers[6],
redo : true,// 한번더 뽑을래?
})
}, 7000);
}
componentDidMount(){
this.runTimeouts();
}
componentDidUpdate(prevProps, prevState){
console.log("리랜덩");
if(this.state.winBalls.length === 0){
this.runTimeouts();
}
}
componentWillUnmount(){
this.timeouts.forEach((v)=>{
clearTimeout(v);
})
}
onClickRedo = () => {
this.setState({
winNumbers : getWinNumbers(), //당첨숫자
winBalls :[],
bonus : null, //보너스공
redo : false,
});
this.timeouts=[];
}
render(){
const {winBalls, bonus, redo} = this.state;
return (
<>
<div>당첨숫자</div>
<div id="result">
{winBalls.map((v)=> <Ball key={v} number={v}/>)}
</div>
<div>보너스!</div>
{bonus && <Ball number={bonus}/>}
{redo && <button onClick={this.onClickRedo}>한번 더!</button>}
</>
)
}
}
module.exports = Lotto;
Hooks 사용
const React = require('react');
const {useState, useRef, useEffect, useMemo, useCallback} = React;
const Ball = require('./Ball');
//훅 특성상 전체 다시 실행함.
//getWinNumbers 의 로또부분 미리 저장해야함, memo
//useCallback 은 함수자체를 기억. memo는 값을 기억. 필수로 적용해야할 때, 자식컴포넌트에 함수넘길때는 반드시 해야함.
//배열이 바뀌면 새로 다시 시작함.
//componentDidUpdate안에 if로 분기처리하면 useEffect도 분기처리된 수만큼 나눠서 처리해야함.
//숫자 미리뽑기
function getWinNumbers(){
console.log('getWinNumbers');
const candidate = Array(45).fill().map((v,i) => i+1);
const shuffle =[];
while(candidate.length>0){
shuffle.push(candidate.splice(Math.floor(Math.random() * candidate.length), 1)[0]);
}
const bonusNumber = shuffle[shuffle.length-1];
const winNumbers = shuffle.slice(0,6).sort((p,c) => p-c);
return [...winNumbers, bonusNumber];
}
const LottoHook =()=>{ //훅스는 선언하는 순서가 중요함. 바꾸면 안됨. 조건문안에는 절대로 넣으면 안됨. 훅스 안에 훅스 넣으면 안댐.
const lottoNumbers = useMemo (()=> getWinNumbers(),[]); //useMemo는 값을 기억한다 []이 바뀌기 전까지.
const [winNumbers, setWinNumbers] = useState(lottoNumbers);
const [winBalls, setWinBalls] = useState([]);
const [bonus, setBonus] = useState(null);
const [redo, setRedo] = useState(false);
const timeouts = useRef([]);
//ajax 같이 componentDidUpdate만 하고싶을때 쓰는 꼼수패턴
const mounted = useRef(false);
useEffect(()=> {
if(!mounted.current){
mounted.current = true;
}else{
//ajax
}
},[/*바뀌는값*/]); //이건 익혀두면 좋다.
useEffect(()=>{
runTimeouts();
return () => {
timeouts.current.forEach((v)=>{
clearTimeout(v);
});
}
},[timeouts.current]); //바뀌는 시점을 넣어주면됨.
onClickRedo = useCallback(() => { //useCallback은 함수를 기억한다. []이 바뀌기 전까지.
console.log(winNumbers);
setWinNumbers(getWinNumbers());
setWinBalls([]);
setBonus(null);
setRedo(false);
timeouts.current=[];
},[winNumbers]); //바뀌어야하는걸 넣어줌. 안넣으면 winNumbers 처음값 그대로 가지고있음. 뭐 useCallback 안쓰면 상태는 초기화됨.
runTimeouts = () => {
for(let i =0; i<winNumbers.length-1; i++){
timeouts.current[i] = setTimeout(()=>{
setWinBalls((prevBall) => [...prevBall, winNumbers[i]]);
}, (i+1) * 1000);
}
timeouts.current[6] = setTimeout(()=>{
setBonus(winNumbers[6]);
setRedo(true);
}, 7000);
}
return (
<>
<div>당첨숫자</div>
<div id="result">
{winBalls.map((v)=> <Ball key={v} number={v}/>)}
</div>
<div>보너스!</div>
{bonus && <Ball number={bonus}/>}
{redo && <button onClick={onClickRedo}>한번 더!</button>}
</>
);
}
module.exports = LottoHook;
반응형
'프로그래밍 > ReactJS' 카테고리의 다른 글
웹팩 자동빌드하기 (0) | 2019.05.09 |
---|---|
웹팩(webPack) + 바벨 설정하기. (2) | 2019.05.08 |
Redux (0) | 2019.04.25 |
리액트 CSS관련 라이브러리 (0) | 2019.04.24 |
리액트 라이프싸이클 (0) | 2019.04.24 |
Comments