먼저 main component생성 -> src파일 안에 sign-in-form.jsx & sign-up-form.jsx 파일 생성
const SignInForm = () =>{ return <div/> } export default SignInForm
기본 컴포넌트의 시작의 위와 같은 형태로 시작한다고 인지하면 도움이된다.
함수이며 html을 반환하는 함수/ export로 반환하여 다른 컴포넌트와 함께 활용할수있다.
SignUpForm도 같은 형태로 컴포넌트를 생성해주자.
렌더링될 Main 컴포넌트도 동일한 형태로 시작하며 Wrapper태그 안에 SignInForm , SignUpForm 태그를 넣어주자
const Main = () => {
return <Wrapper>
<SignInForm/>
<SignUpForm/>
</Wrapper>
}
우리는 js파일에 css문법 작성이 가능한 style-components를 활용해볼것이다
React는 JSX를 사용해서 이미
JavaScript가 HTML을 포함하고 있는 형태를 취하고 있는데, 여기에 CSS-in-JS 라이브러리만 사용하면 CSS도 손쉽게 JavaScript에 삽입할 수 있습니다.
$ npm i styled-components
// 설치 명령어
설치 후에 package.json에 styled-components가 추가된 것을 확인할 수 있습니다.
"dependencies": {
"styled-components": "^6.1.11",
}
그후 위에서 설치한 styled 함수를 임포트하여 사용할수있다.
import styled from 'styled-components'
Wrapper태그에 다음과 같은 형태로 css를 적용시킨 후
const Wrapper = styled.div
height: calc(100vh - 140px); display: flex; flex-direction: column; justify-content: center; align-items: center;
npm -start를하게되면 메인 컴포넌트 안에 내용들과 작성된 css까지 잘 입힌 모습을 확인할 수 있다.
그런데
스타일 컴포넌트(Wrapper)와 일반 컴포넌트(SignInForm)를 육안으로 분리하기 힘들다.
스타일 컴포넌트를 분리하여 객체로 만들어 사용해보자!
const S = { Wrapper : Wrapper } // 위와 같이 키와 value(값)이 같으면 --- const S = { Wrapper } //이렇게 축약해 사용할수있다.
위와 같은 형태로 객체로 분리하여 만들어준후 분간하기 어려웠던
스타일 컴포넌트(Wrapper) 앞에 .접근법을 활용하여 (S.Wrapper) 로 분간해주자
이제 밑과 같은 형태로 스타일 이들어가있는 Wrapper안에 Header와 Container도 만들어줄것이다.
<Wrapper>
<Container>
</Header>
</SignInForm>
</SignUpForm>
<Container/>
<Wrapper/>
작성 후 컨테이너와 나머지 컴포넌트에도 모두 스타일을 적용시켜주자
Wrapper와 같이 Container,Header,SignIn,Signup 모두 스타일을 적용시켜주었다.
const Main = () => {
return <S.Wrapper>
<S.Container>
<S.Header>
<S.Tab>Sign-In</S.Tab>
<S.Tab>Sign-Up</S.Tab>
</S.Header>
<SignInForm/>
<SignUpForm/>
</S.Container>
</S.Wrapper>
}
- 스타일을 모두 담은 메인 컴포넌트 완성
그렇게 되면 Sign in form 과 up form이 두개 다 보이며 마우스가 hover 되어있을때에만 색이 바뀐는 것을 볼수있다
&:hover{ background-color: #0fe9e5; } Tab 스타일 컴포넌트 에 hover하면 색이 바뀌도록 설정해주었다.
내가 해야할일은 Sign in 을 클릭했을때 색이 들어오며 Sign in form 만 보이는것을 원하기 떄문에 그에 맞춰서 다시 코드를 짜보자
먼저 sign in form과 up form을 나누어주기위해 변수를 설정해주자
Main 컴포넌트 안에 let formState = "SIGN-IN"을 작성한다
(만약 변수 안에 불리언 값이 들어간다면 is를 붙여주는것이 좋다 ex let isFormSignIn = true)
들어가기전 내가 변수를 왜 선언했는지 어떻게 사용할것인지 다시 한번 생각해보자
{
formState === 'SIGN-IN' ? <SignInForm/> : <SignUpForm/>
}
삼항 연산자를 활용해 fromState가 'SIGN-IN'이 맞다면(true) SignInForm을 보여주고 아니라면 SignUpForm 을 보여줘라!
(formState가 자바스크립트 변수이기 때문에 중괄호{}를 꼭 써줘야한다)
<S.Tab isSelected={formState === 'SIGN-IN'}>Sign-In</S.Tab>
<S.Tab isSelected={formState === 'SIGN-UP'}>Sign-Up</S.Tab>
첫번째 탭 Sign-In 이 선택되는 기준은 방금 위에서 작성한 코드 "formState === 'SIGN-IN'"
( formState의 값이 'SIGN-IN'이 맞냐!이다)
위 처럼 작성해줌으로써 props의 값이 Tab에 전달된것이다.
값을 사용하기 위해서 스타일을 작성한 Tab에
콜백함수${() => {}}를 작성하여 전달한 값을 가져온다
${(props) => props.isSelected && 'backgroundColor: #e0e0e0'}
const Tab = styled.div`
width: 50%;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
font-size: 28px;
padding: 16px;
font-weight: 600;
${(props) => props.isSelected && 'backgroundColor: #e0e0e0'}
&:hover{
background-color: #e0e0e0;
}
`
전달이 완료되었다면 클릭 이벤트를 부여해보자
각각 SIGN IN 과 SIGN UP을 클릭하게되면 어떻게 실행될지 예상해보자.
클릭하는 버튼에 따라 formstate 값이 바뀌게 될것이다.
(그렇다면 변수에 "SIGN-IN"이 아니라 숫자 0이나 아무런 값을 넣어도 상관이 없는걸까?)
이벤트 함수 정의하기 (이벤트를 정의할때 hadle,On 자주씀)
const handlePressSignTab = () = {}
> const handlePressSignTab = (tabName) => {
formState = tabName
}
// 왜"SIGN-IN"을 매개변수로 받을까..?
// handlePressSignTab의 기능을 다시한번 생각해보자
그후 직접 클릭이되는 S.Tab에 OnClick이벤트를 부여해줄것이다.
먼저 이벤트를 부여할 handlePressSignTab에 매개변수("SIGN-IN")를 넣어줄것이다
주의할점
ONclick이벤트의 함수는 콜백 함수의 형태로 들어가야만한다.
onClick={handlePressSignTab("SIGN-IN")} -> 실행(x)
onClick={() => handlePressSignTab("SIGN-IN")} -> 실행(o)
만약 handlePressSignTab에 tab name이 아닌 event만 받고싶다면
onClick에 함수만 넣어주면 된다. onClick={handlePressSignTab} 매개변수로 event가 들어오게 된다.
const handlePressSignTab = (event) => { formState = tabName }
위에 이벤트와 모든 조건을 맞추었으나 화면은 바뀌지 않는다 왜냐하면 리액트는 state를 통해 화면이 랜더링되기때문애
변수를 useState를 통해 상태로 바꾸어줘야한다.
state를 활용하기 전에 코드의 순회를 통해 중복을 없애보자
먼저 배열
``` const TAB_ARRAY = [
{
name: "SIGN-IN",
isSelected: formState === "SIGN-IN"
},
{
name: "SIGN-UP",
isSelected: formState === "SIGN-UP"
},
]
를 생성해준후
{/* <S.Tab isSelected={formState === 'SIGN-IN'}
onClick={() => handlePressSignTab("SIGN-IN")}>SIGN-IN</S.Tab>
<S.Tab isSelected={formState === 'SIGN-UP'}
onClick={() => handlePressSignTab("SIGN-IN")}
>SIGN-UP</S.Tab> */}
전에 생성한 위 코드를 대신 map을 통해 순회를 시키며 위에 보이는 중복된 코드를 생략해보자
{TAB_ARRAY.map((tab) => <S.Tab
$isSelected={tab.isSelected}
onClick={()=>handlePressSignTab(tab.name)}
>
{tab.name}
</S.Tab>)}
로 간단하게 완성 시켜줄수있다.
나만의 코드 해석
먼저 TAB_ARRAY라는 배열을 생성했다.그 후 map을 통해 순회 시켜주었다.
순회를 시킴으로 <S.tab>을 배열 안의 갯수 만큼 생성해주었다. handlePressSignTab(tab.name) 의 tab.name은 배열안의 name: "SIGN-IN" 아니면 "SIGN-UP"일 것이다.
이렇게 배열을 통해 전달받은 tab.name이 다시 매개변수로 handlePressSignTab 함수의 tabName이라는 매개변수로 받아져
handlePressSignTab 함수의 기능 formState = tabname이라는 기능을 실행 시켜줄것이다.
그렇다면 $isSelected={tab.isSelected} 의 기능은?
// 위에서 정의 하였다.다시 정의 해보자
이제 배열이 추가 될때마다 S.css가 좀더 간편히 추가될것이다.
그리고 map 사용시 주의할점으로 항상 키값을 추가해주는것을 잊으면 안된다.
key = {tab.name}을 하게된다면 겹치게 되니 index를 활용하여
key = {tab.index}를 사용해주자
이제 Sign-In-Form css를 작성해볼것이다.
--공용 컴포넌트 만들기!
지금까지는 스타일 컴포넌트에 props를 전달해보았다 이제 실제 컴포넌트에 props를 전달하는법을 배워볼수있도록 하자
1. props알고가기
2. 구조분해할당
3. 나머지 매개변수 연산자