[2-1] React를 배워야하는 이유
[2-2] React 컴포넌트
[2-3] 클래스형 컴포넌트 vs 함수형 컴포넌트
[2-4] React-Hooks
[2-5] state 친구들 (state, setState, useState)
대표적인 프론트엔드 도구로는 React
, Angular
, Vue
가 있다.
이 가운데, React를 배워야 하는 여러가지 이유가 있다.
⏩ 가장 많은 사용자 수
⏩ 웹, 안드로이드, IOS, 데스크톱을 동시에 만들 수 있다.
React
는 웹
을 만드는 도구다.
React-Native
는 모바일 앱
을 만드는 도구다.
Electron
은 React로 만들어진 웹사이트를 한글, PPT와 같은 데스크톱 프로그램
에서 실행되도록 하는 도구다.
컴포넌트
란 UI 또는 기능을 부품화해서 재사용 가능하게 하는 것
동일한 UI를 재활용하고, 안에 데이터와 이미지만 바꿔준다.
💡 컴포넌트는
복사/붙여넣기
와는 다르다.컴포넌트
는 원본 하나를 만들어서 뿌려주는 개념이다.
⏩ 리액트 컴포넌트를 만들 때
import React from 'react';
⏩ 코드의 최하단
export default Hello;
⏩ App.js
import React from 'react'; import Hello from './Hello'; function App() { return ( <div> <Hello /> </div> ); } export default App;
React에서 컴포넌트 작성 방법은 2가지가 있다.
⏩함수형 컴포넌트란?
함수형 컴포넌트란 함수를 기반으로 작성하는 컴포넌트다.
기존에 사용했던 클래스형 컴포넌트에 비해 휠씬 짧고 직관적인 코드를 짤 수 있다.
💡 그렇다면 왜 함수형 컴포넌트로 바꿔야할까?
- 클래스의 문법이 어렵다.
- 축소가 어렵다.
- reloading의 신뢰성이 떨어진다.
- 최신 기술의 적용이 효과적이지 않다.
💡 함수형이 훠씬 간단하나 클래스형 컴포넌트를 알아야하는 이유
- 기존에 클래스형으로 만든 큰 프로젝트를 모두 함수형으로 바꾸기 어렵다.
- 클래스 형으로 만들었지만, 부분 부분 함수형으로 변경하는 경우
- 내가 검색한 자료가 클래스형인 경우
함수형 컴포넌트
그 자체만으로는 클래스형 컴포넌트
의 모든 기능을 흉내낼 수 없다.
함수형 컴포넌트에서도 클래스형 컴포넌트와 동일한 기능을 사용 가능하도록 도구를 만들어 주었습니다. 이 도구를 Hooks(훅)
이라고 부른다.
Hooks 는 리액트 v16.8 에 새로 도입된 기능이다. 함수형태의 컴포넌트에서 사용되는 몇가지 기술을 Hook이라고 부른다.
함수형 컴포넌트에서도 상태 관리를 할 수 있는 useState
, 그리고 렌더링 직후 작업을 설정하는 useEffect
등의 기능 등을 제공한다.
💡 Hook 의 기능
- State Hook
- useState
Effect Hook - useEffect
state
: 리액트 컴포넌트에서 데이터를 담기 위한 상자 즉, state는 컴포넌트에서 사용하는 변수
state
: 컴포넌트에서 사용하는 변수(state)
setState
: 컴포넌트에서 사용하는 변수(state)를 바꿔주는 기능
useState
: 컴포넌트에서 사용하는 변수(state)를 만들어주는 기능
⏩ 자바스크립트 변수 let(또는 상수 const) 를 사용과 state는 컴포넌트에서 사용 변수 비교
📚 코드캠프
import { useState } from "react"
import {
Wrapper,
Container,
//--------------------> Box :)
InPutBox,
TwoBox,
HeaderBox,
AddressBox,
YoutubeBox,
AttachPicturesBox,
MainSettingBox,
RegistrationBox,
//--------------------> 기타 :)
Title,
Label,
Writer,
Password,
ZipButton,
Pictures,
RadioButton,
RadioLabel,
SubmitButton,
PicturesOut,
RadioOut,
//--------------------> Text :)
WriterText,
PasswordText,
TitleText,
ContentsText,
ZipText,
AddressText,
YoutubeText,
} from "../../styles/index";
export default function BoardsNewPage() {
//-------------------------------------------------------> Input에 들어가는 문구 :)
const [writer, setWriter] = useState("")
const [password, setPassword] = useState("")
const [title, setTitle] = useState("")
const [contents, setContents] = useState("")
const [zip, setZip] = useState("07250")
const [youtube, setYoutube] = useState("")
//---------------------------------------------------------> Input error :(
const [writerError, setWriterError] = useState("")
const [passwordError, setPasswordError] = useState("")
const [titleError, setTitleError] = useState("")
const [contentsError, setContentsError] = useState("")
const [zipError, setZipError] = useState("")
//---------------------------------------------------------->
function onWriter(event) {
setWriter(event.target.value)
}
function onPassword(event) {
setPassword(event.target.value)
}
function onTitle(event) {
setTitle(event.target.value)
}
function onContents(event) {
setContents(event.target.value)
}
//--------------------------------------------------------------->
function onChangeSignup() {
// 1. 검증하기
if (writer === "") {
setWriterError("작성자를 다시 작성해주세요.")
}
if (password === "" && password.length < 3) {
setPasswordError("비밀번호를 다시 작성해주세요.")
}
if (title === "") {
setTitleError("제목을 다시 작성해주세요.")
}
if (contents === "") {
setContentsError("내용을 다시 작성해주세요.")
}
if (writer !== "" && password !== "" && title !== "" && contents !== "") {
alert("회원가입을 축하합니다!!")
}
}
//------------------------------------------------------------->HTML :)
return (
<Wrapper>
<Container>
<HeaderBox>
<Title>게시물 등록</Title>
</HeaderBox>
<TwoBox>
<Writer>
<Label>작성자</Label>
<WriterText type="text" onChange={onWriter} placeholder="이름을 작성해주세요." />
<div>{writerError}</div>
</Writer>
<Password>
<Label>비밀번호</Label>
<PasswordText type="password" onChange={onPassword} placeholder="비밀번호를 작성해주세요." />
<div>{passwordError}</div>
</Password>
</TwoBox>
<InPutBox>
<Label>제목</Label>
<TitleText type="text" onChange={onTitle} placeholder="제목을 작성해주세요." />
<div>{titleError}</div>
</InPutBox>
<InPutBox>
<Label>내용</Label>
<ContentsText type="text" onChange={onContents} placeholder="내용을 작성해주세요." />
<div>{contentsError}</div>
</InPutBox>
<AddressBox>
<Label>주소</Label>
<ZipText type="text" placeholder="07250" />
<ZipButton>우편변호 검색</ZipButton>
<AddressText type="text" placeholder="" />
<AddressText type="text" placeholder="" />
</AddressBox>
<YoutubeBox>
<Label>유튜브</Label>
<YoutubeText type="text" placeholder="링크를 복사해주세요." />
</YoutubeBox>
<AttachPicturesBox>
<Label>사진 첨부</Label>
<PicturesOut>
<Pictures>+</Pictures>
<Pictures>+</Pictures>
<Pictures>+</Pictures>
</PicturesOut>
</AttachPicturesBox>
<MainSettingBox>
<Label>메인 설정</Label>
<RadioOut>
<RadioButton type="radio" name="myaRadio" />
<RadioLabel>유튜브</RadioLabel>
<RadioButton type="radio" name="myaRadio" />
<RadioLabel>사진</RadioLabel>
</RadioOut>
</MainSettingBox>
<RegistrationBox>
<SubmitButton onClick={onChangeSignup}>등록하기</SubmitButton>
</RegistrationBox>
</Container>
</Wrapper>
);
}
import styled from "@emotion/styled";
export const Wrapper = styled.div`
width: 1200px;
/* height: 1847px; */
border: 1px solid black;
margin: 100px;
padding-top: 80px;
padding-bottom: 100px;
padding-left: 102px;
padding-right: 102px;
display: flex;
flex-direction: column;
align-items: center;
border: none;
box-shadow: 0px 0px 10px gray;
`;
export const Container = styled.div`
width: 1000px;
`;
export const HeaderBox = styled.div`
font-weight: 700;
font-size: 36px;
line-height: 53px;
margin-bottom: 50px;
display: flex;
flex-direction: row;
justify-content: center;
cursor: pointer;
`;
export const InPutBox = styled.div`
margin-bottom: 50px;
display: flex;
flex-direction: column;
`;
export const TwoBox = styled.div`
margin-bottom: 50px;
display: flex;
flex-direction: row;
justify-content: space-between;
`;
export const AddressBox = styled.div`
`;
export const YoutubeBox = styled.div`
`;
export const AttachPicturesBox = styled.div`
`;
export const MainSettingBox = styled.div`
`;
export const RegistrationBox = styled.div`
display: flex;
align-items: center;
justify-content: center;
`;
export const Title = styled.div`
`;
export const Label = styled.div`
font-weight: 500;
font-size: 16px;
margin-bottom: 10px;
`;
export const Writer = styled.div`
`;
export const WriterText = styled.input`
width: 486px;
height: 52px;
padding-left: 20px;
`;
export const Password = styled.div`
`;
export const PasswordText = styled.input`
width: 486px;
height: 52px;
padding-left: 20px;
`;
export const TitleText = styled.input`
width: 1000px;
height: 52px;
padding-left: 20px;
`;
export const ContentsText = styled.input`
width: 1000px;
height: 480px;
display: flex;
padding-bottom: 430px;
padding-left: 20px;
`;
export const ZipText = styled.input`
width: 77px;
height: 52px;
margin-right: 20px;
padding-left: 18px;
`;
export const ZipButton = styled.button`
width: 124px;
height: 52px;
background: #000000;
color: white;
border-radius: 3px;
border: none;
cursor: pointer;
`;
export const AddressText = styled.input`
width: 1000px;
height: 52px;
margin-top: 15px;
margin-bottom: 20px;
`;
export const YoutubeText = styled.input`
width: 1000px;
height: 52px;
margin-bottom: 30px;
padding-left: 20px;
`;
export const PicturesOut = styled.div`
display: flex;
`;
export const Pictures = styled.div`
background-color: #BDBDBD;
width: 78px;
height: 78px;
margin-right: 20px;
margin-top: 10px;
margin-bottom: 30px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
&:hover {
background: #aDaDaD;
}
`;
export const RadioOut = styled.div`
display: flex;
margin-bottom: 50px;
`;
export const RadioButton = styled.input`
margin-left: 20px;
`;
export const RadioLabel = styled.div`
margin-left: 10px;
font-weight: 500;
font-size: 16px;
`;
export const SubmitButton = styled.button`
width: 179px;
height: 52px;
background: #FFe600;
border: none;
border-radius: 3px;
font-weight: 500;
font-size: 16px;
cursor: pointer;
&:hover {
background: #FFd600;
}
`;