리액트 프로젝트 만들기

정영찬·2022년 3월 17일
0

프로젝트 실습

목록 보기
1/60

스타일 지정된 구성요소와 React 부드러운 스크롤을 사용해서 React웹 사이트를 구축한다.

Creating-React-Project

새로운 프로젝트를 생성한다.

$ npx create-react-app react-website-smooth-scroll

yarn start로 실행하면 기본 리액트 화면이 나타나는데,프로젝트 제작 불필요한 파일을 제거해준다.

App.css의 내용을 전부 제거하고 아래 내용을 작성한다.

*{
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  font-family: 'Encode Sans Expanded',
  sans-serif;
}

Creating Project Files

  • components : 페이지 구성하는 컴포넌트가 들어있다.

  • images : 페이지에 사용되는 이미지 파일이 들어있다.

  • pages : router를 이용한 페이지가 구현되어있다.

  • videos :페이지에 사용되는 비디오 영상이 들어있다.

Creating Navbar

component 폴더 내부에 Navbar폴더를 생성하고 해당 폴더 안에 2개의 파일을 생성한다.

  • index.js
  • NavbarElements.js

srccomponents/Navbar/index.js에 어떤 컴포넌트들이 들어갈지 대략적으로 작성한다.

const Navbar = () => {
  return (
  <>
    <Nav>
        <NavbarContainer>
            <NavLogo>
                HEY
            </NavLogo>
        </NavbarContainer>
    </Nav>
  </>
  );
};

이런식으로 "나는 Navbar라는 컴포넌트를 만들건데, 그 안에 로고를 만들고싶고, 그걸 감싸는 컨테이너도 있었으면 좋겠다" 라는 느낌으로 작성을 한다. 물론 현재 Nav, NavbarContainer,NavLogo라는 컴포넌트를 정의하지 않았기때문에 빨간줄로 오류가 생겼을 것이다.

Styling Navbar

NavbarElements.js 파일을 코딩한다. styled-components를 사용해서 js파일 내부에 바로 스타일링을 시작한다.
src/components/Navbar/NavbarElements.js

import styled from "styled-components";
import {Link as LinkR} from 'react-router-dom';

export const Nav = styled.div`
  background: #000;
  height: 80px;
  /* margin-top: -80px; */
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 1rem;
  position: sticky;
  top: 0;
  z-index: 10;

  @media screen and(max-width: 960px) {
    transition: 0.8s all ease;
  }
`;

export const NavbarContainer = styled.div`
  display: flex;
  justify-content: space-between;
  height: 80px;
  z-index: 1;
  width: 100%;
  padding: 0 24px;
  max-width: 1100px;
`;

export const NavLogo = styled(LinkR)`
    color:red;
    justify-content:flex-start ;
    cursor:pointer;
    font-size: 1.5rem;
    display: flex;
    align-items: center;
    margin-left: 24px;
    font-weight: bold;
    text-decoration: none;
`

height, display, postion을 설정한다. @media는 단말기의 유형과, 특성이나 수치에 따라 웹사이트나 앱의 스타일을 수정할때 유용하게 사용한다. Link컴포넌트를 사용할 경우 App.js 내부를 BrowserRouter로 감싸주어야 한다. BrowserRouter는 간단히 설명하면 URL과 UI를 동기해주는 <Router>이다.

현재 상황


src/components/Navbar/index.js에 컴포넌트를 추가한다.
-MobileIcon : react-icon에서 가져온 이미지가 들어갈 공간이다.
-FaBars : react-icon종류중 하나 가로 너비가 768px보다 짧아지는 순간 이 NavMenu 대신 이 아이콘이 나타난다.
-NavMenu : 메뉴 항목 컴포넌트인 NavItem을 담는 공간이다.
-NavItem : NavMenu내부에 있는 항목
-NavLinks : NavItem의 라우터 컴포넌트 클릭하면 하단에 테두리가 생긴다.

 <Nav>
        <NavbarContainer>
          <NavLogo to="/">
              LOGO
          </NavLogo>
          <MoblieIcon>
              <FaBars/>
          </MoblieIcon>
          <NavMenu>
              <NavItem>
                  <NavLinks to="about">About</NavLinks>
              </NavItem>
          </NavMenu>
        </NavbarContainer>
      </Nav>

NavBarElements에도 컴포넌트를 추가로 스타일링 한다.

export const MoblieIcon = styled.div`
    display: none;

    @media screen and (max-width: 768px){
        display:block;
        position: absolute;
        top: 0;
        right: 0;
        transform: translate(-100%, 60%);
        font-size: 1.8rem;
        cursor: pointer;
        color: #fff;
    }
`

export const NavMenu = styled.ul`
    display: flex;
    align-items: center;
    list-style: none;
    text-align: center;
    margin-right: -22px;

    @media screen and (max-width: 768px) {
        display: none;
    }
`

export const NavItem = styled.li`
    height: 80px;
`

export const NavLinks = styled(LinkS)`
    color:#fff ;
    display: flex;
    align-items: center;
    text-decoration: none;
    padding: 0 1rem;
    height: 100%;
    cursor: pointer;

    &.active{
        border-bottom: 3px solid #01bf71;
    }
`

index.js로 돌아가서 컴포넌트들을 import 시킨다.

src/components/Navbar/index.js

/* eslint-disable react/jsx-no-undef */
import React from "react";
import {FaBars} from 'react-icons/fa'
import { MoblieIcon, Nav, NavbarContainer, NavItem, NavLinks, NavLogo, NavMenu } from "./NavbarElements";


const Navbar = () => {
  return (
    <div>
      <Nav>
        <NavbarContainer>
          <NavLogo to="/">
              LOGO
          </NavLogo>
          <MoblieIcon>
              <FaBars/>
          </MoblieIcon>
          <NavMenu>
              <NavItem>
                  <NavLinks to="about">About</NavLinks>
              </NavItem>
          </NavMenu>
        </NavbarContainer>
      </Nav>
    </div>
  );
};
export default Navbar;

FaBarsreact-icons에서 가져온것으로 react-icons를 설치해야한다.

npm install react-icons --save

NavLinksreact-scroll을 사용하기 때문에 react-scroll을 설치해야한다.

npm install react-scroll

현재 상황

우측에 NavLinks가 나타난 것을 확인했다. 화면의 너비가 일정 길이보다 짧아질 경우

우측 상단에 아이콘이 나타난다.

NavMenu안에 NavItem을 더 추가했다.

 <NavMenu>
              <NavItem>
                  <NavLinks to="about">About</NavLinks>
              </NavItem>
              <NavItem>
                  <NavLinks to="Discover">Discover</NavLinks>
              </NavItem>
              <NavItem>
                  <NavLinks to="services">Services</NavLinks>
              </NavItem>
              <NavItem>
                  <NavLinks to="signup">Sign Up</NavLinks>
              </NavItem>
          </NavMenu>

현재 상황

NavMenu옆에 로그인 화면으로 이동하는 버튼을 제작한다. NavBtn내부에 NavBtnLink를 생성해서 signin페이지로 경로를 지정한다.

<NavBtn>
              <NavBtnLink to='/signin'>Sign in</NavBtnLink>
</NavBtn>

해당 컴포넌트들을 스타일링한다.
-NavBtn : NavBtnLink를 감싸는 컴포넌트로 너비가 768px보다 좁아지면 사라진다.
-NavBtnLink : 클릭하면 signin페이지로 이동하는 라우터 컴포넌트. 마우스 커서를 올리면 색이 변경된다.


export const NavBtn = styled.nav`
    display: flex;
    align-items: center;

    @media screen and (max-width: 768px){
        display: none;
    }
`

export const NavBtnLink = styled(LinkR)`
    border-radius: 50px;
    background: #01bf71;
    white-space : nowrap;
    padding: 10px 22px;
    color: #010606;
    font-size: 16px;
    outline: none;
    border: none;
    cursor: pointer;
    transition: all 0.2s ease-in-out;
    text-decoration: none;

    &:hover {
        transition: all 0.2s ease-in-out;
        background: #fff;
        color: #010606;
    }

`

이전의 컴포넌트들처럼, index.js에 import시켜주고 실행해보자.

현재 상황

Create Sidebar/Download Menu

Sidebar 컴포넌트를 제작한다.
compnents폴더 내부에 Sidebar폴더를 생성하고 index.js, SidebarElements.js를 생성한다.

index.js

const Sidebar = () => {
  return (
    <> 
    <SidebarContainer>
        <Icon>
            <CloseIcon/>
        </Icon>
    </SidebarContainer>
    </>
  )
}

SidebarContainer : MobileIcon에 있는 FaBar를 클릭하면 나타나는 Sidemenu 창의 레이아웃
Icon : SideMenu 화면
CloseIcon : SideMenu를 닫는 버튼

Styling Sidebar

SidebarElements.js에 해당 컴포넌트들을 스타일링한뒤 export 한다.

import styled from 'styled-components';
import {FaTimes} from 'react-icons/fa';


export const SidebarContainer = styled.aside`
    position: fixed;
    z-index: 999;
    width: 100%;
    height: 100%;
    display: grid;
    align-items: center;
    top: 0;
    left: 0;
    transition: 0.3s ease-in-out;
    opacity: ${({isOpen}) => (isOpen ? '100%' : '0')};
    top : ${({isOpen}) => (isOpen ? '0' : '-100%')};
`;


export const CloseIcon = styled(FaTimes)`
    color: #fff
`;

export const Icon = styled.div`
    position: absolute;
    top: 1.2rem;
    right: 1.5rem;
    background: transparent;
    font-size: 2rem;
    cursor: pointer;
    outline: none;
`

App.jssrc/components/Sidebar/index.js에서 import 시킨다.

function App() {
  return (
   <Router>
     <Sidebar/>
    <Navbar/>
    </Router>
  );
}
/* eslint-disable react/jsx-no-undef */
import React from 'react'
import { CloseIcon, Icon, SidebarContainer } from './SidebarElements'

const Sidebar = () => {
  return (
    <> 
    <SidebarContainer>
        <Icon>
            <CloseIcon/>
        </Icon>
    </SidebarContainer>
    </>
  )
}

export default Sidebar

`

실행을 시켜도 현재는 기본 화면과 같지만, isOpen조건문을 주석처리하면 아래와 같이 나타난다.


우측 상단에 react-icons에서 가져온 FaTimes아이콘이 나타난다.

사용자가 MobileIcon을 클릭 하면 위의 사이드메뉴가 나타나고, NavBarNavItem항목들이 나타나야한다. 따라서 해당 Item들을 SideBar에서도 작성한다.

const Sidebar = () => {
  return (
    <> 
    <SidebarContainer>
        <Icon>
            <CloseIcon/>
        </Icon>
        <SidebarWrapper>
          <SidebarMenu>
            <SidebarLink to="about">
              About
            </SidebarLink>
            <SidebarLink to="discover">
              Discover
            </SidebarLink>
            <SidebarLink to="services">
              Services
            </SidebarLink>
            <SidebarLink to="signup">
              Sign Up
            </SidebarLink>
          </SidebarMenu>
          <SideBtnWrap>
            <SidebarRoute to="/singin">Sign In</SidebarRoute>
          </SideBtnWrap>
        </SidebarWrapper>
    </SidebarContainer>
    </>
  )
}

SidebarWrapper : 사이드바 메뉴 와 회원가입 버튼을 표시하는 외부 wrapper
SidebarMenu : 사이드바 메뉴 항목을 담아놓은 ul
SidebarBtnWrap : 회원가입 버튼 레이아웃
SidebarRoute : 회원가입 버튼. 누르면 signin페이지로 이동한다.

SidebarElements.js에서 추가로 스타일링을 작성한다.

export const SidebarWrapper = styled.div`
    color:#fff;
`

export const SidebarMenu = styled.ul`
    display: grid;
    grid-template-columns: 1f;
    grid-template-rows: repeat(6, 80px); 
    text-align: center;

    @media screen and (max-width: 480px){
        grid-template-rows: repeat()(6, 60px);
    }
`

export const SidebarLink = styled(LinkS)`
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
    text-decoration: none;
    list-style: none;
    transition: 0.2s ease-in-out;
    color: #fff;
    cursor: pointer;

    &:hover{
        color: #01bf71;
        transition: 0.2s ease-in-out;
    }
`

export const SideBtnWrap = styled.div`
    display: flex;
    justify-content:center;
`

export const SidebarRoute = styled(LinkR)`
    border-radius: 50px;
    background: #01bf71;
    white-space: nowrap;
    padding: 16px 64px;
    color: #010606;
    font-size: 16px;
    outline: none;
    border: none;
    cursor: pointer;
    transition: all 0.2s ease-in-out;
    text-decoration: none;

    &:hover{
        transition: all 0.2s ease-in-out;
        background: #fff;
        color: #010606;
    }
`

src/components/Sidebar/index.js에 컴포넌트들을 추가로 import 한다.

/* eslint-disable react/jsx-no-undef */
import React from 'react'
import { CloseIcon, Icon, SidebarContainer, SidebarLink, SidebarMenu, SidebarRoute, SidebarWrapper, SideBtnWrap } from './SidebarElements'

const Sidebar = () => {
  return (
    <> 
    <SidebarContainer>
        <Icon>
            <CloseIcon/>
        </Icon>
        <SidebarWrapper>
          <SidebarMenu>
            <SidebarLink to="about">
              About
            </SidebarLink>
            <SidebarLink to="discover">
              Discover
            </SidebarLink>
            <SidebarLink to="services">
              Services
            </SidebarLink>
            <SidebarLink to="signup">
              Sign Up
            </SidebarLink>
          </SidebarMenu>
          <SideBtnWrap>
            <SidebarRoute to="/singin">Sign In</SidebarRoute>
          </SideBtnWrap>
        </SidebarWrapper>
    </SidebarContainer>
    </>
  )
}

export default Sidebar

현재상황

SideBar의 메뉴 항목과 아래에 회원가입 버튼이 생성되었다.

Creating Home Page

App.js에 현재 SidebarNavBar 컴포넌트가 있는데 이 둘을 합친 Home이라는 컴포넌트를 생성한다.

src/pagesindex.js파일을 생성한다.

import React from 'react'
import Navbar from '../components/Navbar'
import Sidebar from '../components/Sidebar'

const Home = () => {
  return (
    <> 
    <Sidebar/>
    <Navbar/>
    </>
  )
}

export default Home

그리고 AppHome 컴포넌트를 불러와서 수정한다.

function App() {
  return (
   <Router>
    <Home/>
    </Router>
  );
}

MobileIcon을 클릭했을때 사이드 메뉴가 나타나게끔 function을 작성할 것이다.

src/pages/index.jsuseState를 이용하여 isOpen의 상태를 관리할 것이다.

  const [isOpen,setIsOpen] = useState(false)
    
    const toggle = () => {
        setIsOpen(!isOpen)
    }

이렇게만 쓸게 아니라 해당 컴포넌트에 필요한 props들을 넘겨줘야 한다. 왜냐하면 Sidebar를 스타일링 할 때, isOpen의 값에 따라 나타나게 설정했고 , CloseIcon을 터치하면 사라지게 해주는 함수를 받아와야하기 때문이다.
따라서 Navbar컴포넌트에는 toggle을, Sidebar컴포넌트에는 isOpentoggle을 보내줘야한다.

  return (
    <> 
    <Navbar toggle={toggle}/>
    <Sidebar isOpen={isOpen} toggle={toggle}/>
    </>
  )

받은 props들을 이용하여 해당 컴포넌트에 알맞는 위치에 사용되게끔 toggle, isOpen을 배치한다.
Navbar/index

<MoblieIcon onClick={toggle}>
              <FaBars/>
</MoblieIcon>

Sidebar/index

<SidebarContainer isOpen={isOpen} onClick={toggle} >
        <Icon onClick={toggle}>
 <CloseIcon/>
        </Icon>

현재상황

MobileIcon을 클릭하면 사이드메뉴가 나타나고 CloceIcon혹은 SideBarContainer내부 요소를 제외한 공간을 터치하면 다시 사라지게 된다.

사이드 메뉴중 하나를 클릭하면 해당 내용으로 이동하게 하려면 먼저 사이드 메뉴창이 닫혀야 하기 때문에 SidebarLink에도 toggle props 를 추가한다.

		  <SidebarMenu>
            <SidebarLink to="about" onClick={toggle}>
              About
            </SidebarLink>
            <SidebarLink to="discover" onClick={toggle}>
              Discover
            </SidebarLink>
            <SidebarLink to="services" onClick={toggle}>
              Services
            </SidebarLink>
            <SidebarLink to="signup" onClick={toggle}>
              Sign Up
            </SidebarLink>
          </SidebarMenu>
profile
개발자 꿈나무

0개의 댓글