
이번 글을 통해 배워갈 내용
- 리액트 훅 함수 기반으로 생성자 구현해보기


여기 귀여운 고양이가 있습니다
중앙 버튼을 누르면 고양이가 말하는 기능이 토글 되고
하단에 버튼을 누르면 함수기반 그리고 클래스 기반으로 변경되게 세팅했습니다.
먼저 클래스에서 생성자를 세팅하는 것부터 보겠습니다.
생성자는 ES6에서 클래스와 함께 등장한 개념으로
클래스에 인스턴스가 생성되면 가장 먼저 실행되는 메서드로서
주로 인스턴스의 초기값들을 세팅해줍니다.
생성자를 클래스에서 세팅하는 경우 아래와 같이
간단하게 세팅할 수 있습니다.
export default class TestCl extends Component {
constructor(props) {
super(props);
this.state = {
isTalking: false,
};
console.log( "생성자 한번만 실행");
}
render = () => {
return (
<Container>
{this.state.isTalking ? <Cat /> : <TalkingCat />}
<button
onClick={() =>
this.setState((prevState) => {
return { isTalking: !prevState.isTalking };
})
}
>
class talking: {this.state.isTalking ? "true" : "false"}
</button>
</Container>
);
};
}
위에서 보시는 것과 같이 생성자는 constructor를 선언해서 세팅해주면 됩니다.
(styled component를 사용한 부분은 아래에 전체 코드가 있습니다)
자 그러면 훅에서는 생성자를 어떻게 세팅할까요?
정답은 훅에서는 생성자를 세팅하지 않는다입니다.
리액트 버전 16.8부터 React 요소로 추가된 Hook은 클래스 바탕의 코드를 사용하지 않고
인스턴스를 만들고 생성자에서 이벤트 핸들러를 바인딩하는 비용과 같이 클래스에 필요한 많은 오버헤드를 줄여줍니다.
하지만 진짜 훅에 생성자 비슷하게 해서
처음 실행될 때 한 번만 실행되는 생성자 비슷한 기능을 만들고자 한다면?
아래와 같이 만드는 것도 하나의 방법이라 생각합니다.
const useConstructor = (callBack = () => {}) => {
const hasBeenCalled = useRef(false);
if (hasBeenCalled.current) return;
callBack();
hasBeenCalled.current = true;
}
const TestFn = () => {
const [isTalking, setIsTalking] = useState(false);
useConstructor(() => {
console.log( "useConstructor 실행 (initial render 전에 한번만 실행)");
});
return (
<Container>
{isTalking ? <Cat /> : <TalkingCat />}
<button onClick={() => setIsTalking(!isTalking)}>function talking : {isTalking ? "true" : "false"}</button>
</Container>
);
}
export default TestFn;
useConstructor라는 임의의 함수를 만들어서 테스트해보았습니다.
여기에 비교를 위해서 useEffect 도 추가해보겠습니다.
const useConstructor = (callBack = () => {}) => {
const hasBeenCalled = useRef(false);
if (hasBeenCalled.current) return;
callBack();
hasBeenCalled.current = true;
}
const TestFn = () => {
const [isTalking, setIsTalking] = useState(false);
useConstructor(() => {
console.log( "useConstructor 실행 (initial render 전에 한번만 실행)");
});
useEffect(()=> {
console.log( "isTalking useEffect 실행");
}, [isTalking])
useEffect(()=> {
console.log( "[] useEffect 실행");
}, [])
return (
<Container>
{isTalking ? <Cat /> : <TalkingCat />}
<button onClick={() => setIsTalking(!isTalking)}>function talking : {isTalking ? "true" : "false"}</button>
</Container>
);
}
export default TestFn;
자 그러면 테스트를 해보겠습니다.
두 함수를 아래와 같이 준비된 부모 컴포넌트에서 불러오면
import TestCl from '../components/TestCl'
import TestFn from '../components/TestFn'
import React, { useState } from "react";
import styled from "styled-components";
const ChangeTestBtn = styled.button`
width: 200px;
height: 100px;
z-index: 100;
position: fixed;
bottom: 100px;
right: 100px;
`;
export default function Home() {
const [isClass, setIsClass] = useState(false);
return (
<>
{isClass ? <TestCl /> : <TestFn />}
<ChangeTestBtn onClick={() => setIsClass(!isClass)}>function talking : {isClass ? "true" : "false"}</ChangeTestBtn>
</>
)
}
아래와 같이
생성자가 클래스와 훅 기반의 컴포넌트 모두
객체가 처음 호출될 때 한 번만 실행되며
그 뒤로 실행이 안되고
useEffect의 경우 특정 값이 바뀔 때 실행되게 세팅할 수 있는 것을 알 수 있습니다.



전체 코드는 아래와 같습니다.
styled 컴포넌트를 사용하였습니다.
import React, { useEffect, useCallback, useRef, useState } from "react";
import styled, { keyframes } from "styled-components";
const talk = keyframes`
0% {background-image: url('/Sprite0001.png');}
40% {background-image: url('/Sprite0002.png');}
60% {background-image: url('/Sprite0003.png');}
80% {background-image: url('/Sprite0002.png');}
100% {background-image: url('/Sprite0001.png');}
`;
const Cat = styled.div`
width: 300px;
height: 300px;
background-size: cover;
animation: ${talk} 2s linear infinite;
`;
const TalkingCat = styled.div`
width: 300px;
height: 300px;
background-size: cover;
background-image: url('/Sprite0001.png');
`;
const Container = styled.div`
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background-color: #ecce;
`;
const useConstructor = (callBack = () => {}) => {
const hasBeenCalled = useRef(false);
if (hasBeenCalled.current) return;
callBack();
hasBeenCalled.current = true;
}
const TestFn = () => {
const [isTalking, setIsTalking] = useState(false);
useConstructor(() => {
console.log( "useConstructor 실행 (initial render 전에 한번만 실행)");
});
useEffect(()=> {
console.log( "isTalking useEffect 실행");
}, [isTalking])
useEffect(()=> {
console.log( "[] useEffect 실행");
}, [])
return (
<Container>
{isTalking ? <Cat /> : <TalkingCat />}
<button onClick={() => setIsTalking(!isTalking)}>function talking : {isTalking ? "true" : "false"}</button>
</Container>
);
}
export default TestFn;
import React, { Component } from "react";
import styled, { keyframes } from "styled-components";
const talk = keyframes`
0% {background-image: url('/Sprite0001.png');}
40% {background-image: url('/Sprite0002.png');}
60% {background-image: url('/Sprite0003.png');}
80% {background-image: url('/Sprite0002.png');}
100% {background-image: url('/Sprite0001.png');}
`;
const Cat = styled.div`
width: 300px;
height: 300px;
background-size: cover;
animation: ${talk} 2s linear infinite;
`;
const TalkingCat = styled.div`
width: 300px;
height: 300px;
background-size: cover;
background-image: url('/Sprite0001.png');
`;
const Container = styled.div`
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background-color: #ecce;
`;
export default class TestCl extends Component {
constructor(props) {
super(props);
this.state = {
isTalking: false,
};
console.log( "생성자 한번만 실행");
}
render = () => {
return (
<Container>
{this.state.isTalking ? <Cat /> : <TalkingCat />}
<button
onClick={() =>
this.setState((prevState) => {
return { isTalking: !prevState.isTalking };
})
}
>
class talking: {this.state.isTalking ? "true" : "false"}
</button>
</Container>
);
};
}
참조 및 인용
https://codemasterkimc.tistory.com/50
300년차 개발자의 좋은 코드 5계명 (Clean Code)
이번 글을 통해 배워갈 내용 좋은 코드(Clean Code)를 작성하기 위해 개발자로서 생각해볼 5가지 요소를 알아보겠습니다. 개요 좋은 코드란 무엇일까요? 저는 자원이 한정적인 컴퓨터 세상에서 좋
codemasterkimc.tistory.com
https://ko.reactjs.org/docs/hooks-intro.html
Hook의 개요 – React
A JavaScript library for building user interfaces
ko.reactjs.org
https://dev.to/bytebodger/constructors-in-functional-components-with-hooks-280m
Constructors in Functional Components With Hooks
[NOTE: Since writing this article, I've encapsulated my little constructor-like utility into an NPM...
dev.to
'Javascript > React' 카테고리의 다른 글
| React Hook State 묶어서 쓰는 한가지 방법 (0) | 2022.03.26 |
|---|---|
| 리액트 SVG로 손글씨 그림그리기 효과 구현해보는 한가지 방법 (0) | 2022.03.12 |
| 리액트 훅을 이용해 카메라 CSS 제작 및 촬영 기능 추가하는 한가지 방법 (0) | 2022.03.01 |
| 리액트 훅을 사용해서 캔버스에 움직이는 하트 애니메이션 만들기 (0) | 2022.02.25 |
| VS코드 리액트 개발의 필수 아이템 Simple React Snippets (0) | 2021.08.20 |