[B-singroom]프로젝트 빌딩 3 - Intro 컴포넌트 작성

🚀 Intro 컴포넌트 작성


 첫 화면에서는 심볼 캐릭터와 캐치프레이즈, 그리고 아이콘(이모지)과 닉네임을 선택하여 채팅방에 입장한다.

  다음과 같은 요소들이 사용되었고 이전에 비해서 개선되었다.

  • main.js에서 창 크기를 고정(1200x800)
  • 벨로퍼트님의 리액트 강의 중 '여러개의 input 상태 관리하기'를 응용해 select태그와 input 각각 아이콘, 닉네임을 useState하나로 관리
  • react-router-dom v6는 link태그를 함수적으로 구현할 때 쓰던 useHistory Hook의 네이밍이 useNavigate로 변경됨
  • 기타 정렬을 위한 flexbox
  • Intro.js 안에서만 작성된 코드를 분할하고 일부 하드코딩 된 부분은 필요할 시 수정

Intro.js

import React from 'react';
import styled from 'styled-components';
import mirrorball from "../../img/mirrorball.png";
import bchar from "../../img/B대면인트로캐릭터.png";
import bsing from "../../img/B대면노래방.png";
import Login from "./login"

const Background = styled.div`
    display: flex;
    align-items: center;
    width: 100%;
    height: 100%;
`

const Mirrorball = styled.img`
    width: 155px;
    height: 120px;
    position: absolute;
    top: 0;
    left: 50%;
    transform: translate(-50%, 0%);
`
const Container = styled.div`
    margin: auto;
    width: 90%;
    height: 90%;
    border-radius: 20px; 
    border: 1px solid rgba(255, 255, 255, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
`
const Charactor = styled.div`
    flex: 1;
`
const Enter = styled.div`
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 1;
`
const Bchar = styled.img`
    width: 500px;
    height: 500px;
`

const Bsing = styled.img`
    width: 480px;
    height: 170px;
`

function Intro() {
    return (
        <Background>
             <Mirrorball src={mirrorball}></Mirrorball>
             <Container>
                <Charactor>
                    <Bchar src={bchar}></Bchar>
                </Charactor>
                <Enter src={bsing}>
                    <Bsing src={bsing}></Bsing>
                    <Login></Login>
                </Enter>
             </Container>
        </Background>

    )}
  
  export default Intro;


Login.js
import React, {useState} from 'react';
import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
import CustomButton from '../common';

const Loginform = styled.form`
    width: 400px;
    height: 300px;
    border: 1px solid white;
    background: rgba(255, 255, 255, 0.5);
    border-radius: 50px;   
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    align-content: space-around;
    justify-content: center;
    align-items: center;
`
const IconSel = styled.select`
    width:47px;
    height: 37px;
    border: 1px solid lightgray;
    border-radius: 10px;
    margin-right: 10px;
`
const NameInput = styled.input`
    width: 170px;
    height: 32px;
    border: 1px solid lightgray;
    border-radius: 10px;
`
const Worning = styled.input`
    text-align: center;
    width: 80%;
    margin-bottom: 20px;
    color: red;
    border: none;
    background: transparent;
`

const IconSelect = ({value, onChange, options}) =>{
    return (
		<IconSel name="icon" value ={value} onChange={onChange}>
            <option value="" selected disabled hidden ></option>
			{options.map((option) => (
				<option
					value={option}
				>
					{option}
				</option>
			))}
		</IconSel>
	)
}
function Login(){
    const navigate = useNavigate();

    const Icons = ["🐱","🦝","🐺","🦊","🦁","🐯","🐼","🐨","🐻"]

    const [worning, setWorning] = useState();

    const [inputs, setInputs] = useState({
        nickname: '',
        icon:''
      });
    
    const { nickname ,icon } = inputs; // 비구조화 할당을 통해 값 추출

    const onChange = (e) => {
        const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
        setInputs({
          ...inputs,                      // 기존의 input 객체를 복사한 뒤
          [name]: value                   // name 키를 가진 값을 value 로 설정
        });
      };

    const onSubmit = (e) =>{
        e.preventDefault();

        if(nickname==="" || icon==="") {
            setWorning("icon을 선택하고 nickname을 입력해주세요.")
        }
        else{
            setWorning("입장 중입니다.....")
            navigate('/lobby', {replace:true, state: { nickname : nickname, icon : icon}})
        }
    }

    return (
        <Loginform onSubmit={onSubmit}>
            <p>이모티콘과 닉네임을 입력하세요</p>
            <div style={{margin:"20px"}}>
            <IconSelect name="icon" value={icon} onChange={onChange} options={Icons}></IconSelect>
            <NameInput type="text" name="nickname" placeholder="nickname" value={nickname} onChange={onChange} size="20"/>
            </div>
            <Worning readOnly={true} type="text" value={worning}/>
            <CustomButton type="submit">입장</CustomButton>
        </Loginform>
    )}
export default Login;

Btn.js 필요성이 없어 테마설정은 하지 않았으나 나누어 봄

import React from 'react';
import styled from 'styled-components';

const Btn = styled.button`
    position: relative;
    width: 80px;
    height: 32px;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    background-color:  ${props => props.color || '#EEEEEE'};
    border: 1px solid navy;
    border-radius: 5px;

    box-shadow: 3px 3px navy;

    &:hover {
        background: #FFFFFF;}
    &:active {
        background: #DDDDDD;}
`

function CustomButton({color, children}) {
    return (
        <Btn color={color}>{children}</Btn>
    )}

export default CustomButton;

 다음은 useNavigate훅을 통해 Lobby컴포넌트로 전달 된 아이콘과 닉네임을 통해 User클래스를 작성하고, 인스턴스를 만드는 과정을 구현한다.

완성화면

좋은 웹페이지 즐겨찾기