리액트 훅이 나오기 전까지 클래스 컴포넌트를 메인으로 사용하였다. 그러므로 훅에서 클래스로 변환해본다.
* 리액트는 버전 16.8부터 함수 컴포넌트를 기본 컴포넌트로 사용하기 시작했지만, 그 이전에는 클래스 컴포넌트를 기본 컴포넌트로 사용했다.
기존코드와 변경코드를 비교할때 import, interface, export 또는 class 부분을 비교하면서 보면된다.
기존코드 Button 기존코드 :
더보기
import React from 'react';
import Styled from 'styled-components';
interface ContainerProps {
readonly backgroundColor: string;
readonly hoverColor: string;
}
const Container = Styled.div<ContainerProps>`
text-align: center;
background-color: ${(props) => props.backgroundColor};
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
&:hover {
background-color: ${(props) => props.hoverColor};
}
&:active {
box-shadow: inset 5px 5px 10px rgba(0, 0, 0, 0.2);
}
`;
const Label = Styled.div`
color: #FFFFFF;
font-size: 16px;
`;
interface Props {
readonly label: string;
readonly backgroundColor?: string;
readonly hoverColor?: string;
readonly onClick?: () => void;
}
export const Button = ({
label,
backgroundColor = '#304FFE',
hoverColor = '#1E40FF',
onClick,
}: Props) => {
return (
<Container backgroundColor={backgroundColor} hoverColor={hoverColor} onClick={onClick}>
<Label>{label}</Label>
</Container>
);
};
Button/index.tsx
import React, {Component} from "react";
import Styled from "styled-components";
interface ContainerProps {
readonly backgroundColor: string;
readonly hoverColor: string;
}
const Container = Styled.div<ContainerProps>`
text-align: center;
background-color: ${(props) => props.backgroundColor};
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
&:hover {
background-color: ${(props) => props.hoverColor};
}
&:active {
box-shadow: inset 5px 5px 10px rgba(0, 0, 0, 0.2);
}
`;
const Label = Styled.div`
color: #FFFFFF;
font-size: 16px;
`;
interface Props {
readonly label : String;
readonly backgroundColor?: string;
readonly hoverColor?: string;
readonly onClick?: () => void;
}
export class Button extends Component<Props> {
render() {
const {
label,
backgroundColor = '#304FFE',
hoverColor = '#1E40FF',
onClick,
} = this.props;
return (
<Container backgroundColor={backgroundColor} hoverColor={hoverColor}
onClick={onClick}>
<Label>{label}</Label>
</Container>
);
}
}
Input 기존코드
더보기
import React from 'react';
import Styled from 'styled-components';
const InputBox = Styled.input`
flex: 1;
font-size: 16px;
padding: 10px 10px;
border-radius: 8px;
border: 1px solid #BDBDBD;
outline: none;
`;
interface Props {
readonly placeholder?: string;
readonly value?: string;
readonly onChange?: (text: string) => void;
}
export const Input = ({ placeholder, value, onChange }: Props) => {
return (
<InputBox
placeholder={placeholder}
value={value}
onChange={(event) => {
if (typeof onChange === 'function') {
onChange(event.target.value);
}
}}
/>
);
};
Input/index.tsx
import React, {Component} from "react";
import Styled from "styled-components";
interface Props {
readonly placeholder?: string;
readonly value?: string;
readonly onChange?: (text: string) => void;
}
const InputBox = Styled.input`
flex: 1;
font-size: 16px;
padding: 10px 10px;
border-radius: 8px;
border: 1px solid #BDBDBD;
outline: none;
`;
export class Input extends Component<Props> {
render() {
const {placeholder,value,onChange} = this.props
return (
<InputBox placeholder={placeholder}
value={value}
onChange={(event => {
if(typeof onChange === 'function'){
onChange(event.target.value);
}
})}
/>
);
}
}
ToDoItem 기존코드
더보기
import React from 'react';
import Styled from 'styled-components';
import { Button } from 'Components/Button';
const Container = Styled.div`
display: flex;
border-bottom: 1px solid #BDBDBD;
align-items: center;
margin: 10px;
padding: 10px;
`;
const Label = Styled.div`
flex: 1;
font-size: 16px;
margin-right: 20px;
`;
interface Props {
readonly label: string;
readonly onDelete?: () => void;
}
export const ToDoItem = ({ label, onDelete }: Props) => {
return (
<Container>
<Label>{label}</Label>
<Button label="삭제" backgroundColor="#FF1744" hoverColor="#F01440" onClick={onDelete} />
</Container>
);
};
ToDoItem/index.tsx
import React, {Component} from "react";
import Styled from "styled-components";
import {Button} from "Components/Button";
interface Props {
readonly label: string;
readonly onDelete?:() => void;
}
const Container = Styled.div`
display: flex;
border-bottom: 1px solid #BDBDBD;
align-items: center;
margin: 10px;
padding: 10px;
`;
const Label = Styled.div`
flex: 1;
font-size: 16px;
margin-right: 20px;
`;
export class ToDoItem extends Component<Props> {
render() {
const {label, onDelete} = this.props;
return (
<Container>
<Label>{label}</Label>
<Button label="삭제"
backgroundColor="#FF1744"
hoverColor="#F01440"
onClick={onDelete}/>
</Container>
)
}
}
App.tsx 기존코드
더보기
import React, { useState } from 'react';
import Styled from 'styled-components';
import { Button, Input, ToDoItem } from 'Components';
const Container = Styled.div`
min-height: 100vh;
background-color: #EEEEEE;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
`;
const Contents = Styled.div`
display: flex;
background-color: #FFFFFF;
flex-direction: column;
padding: 20px;
border-radius: 8px;
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.2);
`;
const ToDoListContainer = Styled.div`
min-width: 350px;
height: 400px;
overflow-y: scroll;
border: 1px solid #BDBDBD;
margin-bottom: 20px;
`;
const InputContainer = Styled.div`
display: flex;
`;
function App() {
const [toDo, setToDo] = useState('');
const [toDoList, setToDoList] = useState<string[]>([]);
const addToDo = (): void => {
if (toDo) {
setToDoList([...toDoList, toDo]);
setToDo('');
}
};
const deleteToDo = (index: number): void => {
let list = [...toDoList];
list.splice(index, 1);
setToDoList(list);
};
return (
<Container>
<Contents>
<ToDoListContainer data-testid='toDoList'>
{toDoList.map((item, index) => (
<ToDoItem key={item} label={item} onDelete={() => deleteToDo(index)} />
))}
</ToDoListContainer>
<InputContainer>
<Input
placeholder="할 일을 입력해 주세요"
value={toDo}
onChange={(text) => setToDo(text)}
/>
<Button label="추가" onClick={addToDo} />
</InputContainer>
</Contents>
</Container>
);
}
export default App;
App.tsx
import React, {Component} from 'react';
import Styled from 'styled-components';
import {Button,Input,ToDoItem} from "Components";
const Container = Styled.div`
min-height: 100vh;
background-color: #EEEEEE;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
`;
const Contents = Styled.div`
display: flex;
background-color: #FFFFFF;
flex-direction: column;
padding: 20px;
border-radius: 8px;
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.2);
`;
const InputContainer = Styled.div`
display: flex;
`;
const ToDoListContainer = Styled.div`
min-width: 350px;
height: 400px;
overflow-y: scroll;
border: 1px solid #BDBDBD;
margin-bottom: 20px;
`;
interface Props {}
interface State {
readonly toDo: string;
readonly toDoList: string[];
}
class App extends Component<Props, State>{
constructor(props:Props) {
super(props);
this.state = {
toDo:'',
toDoList : [],
}
}
private addToDo = (): void => {
const {toDo, toDoList} = this.state;
if(toDo){
this.setState({
toDo:'',
toDoList : [...toDoList,toDo],
})
}
}
private deleteToDo = (index: number): void => {
let list = [...this.state.toDoList];
list.splice(index,1);
this.setState({
toDoList : list
})
}
render() {
const {toDo, toDoList} = this.state;
return (
<Container>
<Contents>
<ToDoListContainer data-testid='toDoList'>
{
toDoList.map((item, index) => (
<ToDoItem key={item} label={item} onDelete={() => this.deleteToDo(index)}/>
))
}
</ToDoListContainer>
<InputContainer>
<Input placeholder="할 일을 입력해 주세요" value={toDo} onChange={(text => this.setState({toDo : text}))}/>
<Button label="추가" onClick={this.addToDo}/>
</InputContainer>
</Contents>
</Container>
);
}
}
export default App;
결과
반응형
'2022 > 리액트+TDD(完)' 카테고리의 다른 글
Context API / localStorage - 1 (0) | 2022.01.14 |
---|---|
클래스 컴포넌트 라이프 사이클 (0) | 2022.01.13 |
Props/ State - 7 (0) | 2022.01.09 |
Props/ State - 6 (0) | 2022.01.09 |
Props/ State - 5 (0) | 2022.01.09 |