라이브러리를 사용할때, 보통 class나 id는 지정되있기 마련이죠.

또한 이런 것을 수정해야하는 경우도 종종 생깁니다.

 

이때 css를 수정하는 방법을 알아보도록 하겠습니다.!

(next, styled-components 사용 방법입니다.)

 

첫번째 방법은 css 파일을 import하는 방법입니다.

즉 전체 페이지에 대한 스타일시트를 가져오는 방법입니다.

먼저 pages/ 폴더 하위에 _app.js 파일을 생성한 후 스타일시트를 import해주면 됩니다.

import '../styles.css';

export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

https://nextjs.org/docs/basic-features/built-in-css-support

 

Basic Features: Built-in CSS Support | Next.js

Next.js supports including CSS files as Global CSS or CSS Modules, using `styled-jsx` for CSS-in-JS, or any other CSS-in-JS solution! Learn more here.

nextjs.org

 

두번째 방법은 글로벌 스타일을 만드는 것인데요.

첫번째 방법과는 달리 styled-components라이브러리를 사용하고 있어야합니다.

https://styled-components.com/docs/api#createglobalstyle

 

styled-components: API Reference

API Reference of styled-components

styled-components.com

createGlobalStyle를 import 한 뒤에 

import styled, { createGlobalStyle } from 'styled-components';

styled.div`` 가 아닌, createGlobalStyle로 작업을 하면 됩니다.

(.slick-slide는 라이브러리가 지정한 class이며 스타일 덮여씌우는 예시입니다.)

const Global = createGlobalStyle`
    .slick-slide {
        display: inline-block;
    }
`;

그리고 아무대나 컴포넌트 넣듯 <Global />로 넣으면 됩니다.

이때 간단히 설명하자면 styled.div`` 형식으로 만든 것은 로컬 스코프를 가지게되고, 

createGlobalStyle``로 만든것은 글로벌 스코프를 가지게 된다고 합니다.

 

저는 작업 특성 상 pages/_app.js 파일을 만들었는데,

글로벌 스타일을 이곳에 넣어줬습니다. 

pages/_app.js

import React from 'react';
import PropTypes from 'prop-types';
import Head from 'next/head';
import { createGlobalStyle } from 'styled-components';
import 'antd/dist/antd.css';
import wrapper from '../store/configurestore';

const App = ({ Component }) => {
    const Global = createGlobalStyle`
        .hidden {
            padding: 0; 
            margin: -1px;
            position: absolute; 
            width: 1px; 
            height: 1px; 
            clip: rect(0 0 0 0); 
            overflow: hidden; 
            border: 0; 
        }
    `;

    return(
        <>
            <Head>
                <meta charSet="utf-8" />
                <title>App</title>
            </Head>
            <Global />
            <Component />
        </>
    );
};


App.propTypes = {
    Component: PropTypes.elementType.isRequired,
};

export function reportWebVitals(metric){
    console.log(metric);
}

export default wrapper.withRedux(App);

 

세번째 방법중복되는 기본 스타일을 어떻게 사용할까? 입니다. 

styled-components 라이브러리에서 css api를 제공합니다.

https://styled-components.com/docs/api#css

 

styled-components: API Reference

API Reference of styled-components

styled-components.com

이렇게 사용하면 됩니다.

import styled, { css } from 'styled-components';

const defaultStyle = css`
    display: block;
    // ...
`;

const CircleButton = styled.button`
	${defaultStyled}
    // ....
`;

const RectangleButton = styled.button`
	${defaultStyled}
    // ....
`;

 

이때 css를 넣지않고 백틱만으로도 작업이 되긴 합니다만 권고하지 않습니다.

문자열로 인식되어 원하지 않는 결과가 생길 수도 있다고 합니다.

 

 

 

react에서 리다이렉션 시키려면 모듈을 설치하여 작업해주어야합니다.

하지만 next에서는 따로 설치 없이 간단히 사용할 수 있습니다.

 

로그인하지 않았다면 로그인 화면으로 보내는 작업을 하겠습니다.

next/router 를 통해 작업하기 위해 import를 해줍니다.

import Router from 'next/router';

 

컴포넌트가 생성될 때 실행되어야하기 때문에 useEffect를 통해 작업합니다.

import React, { useEffect } from 'react';

코드는 아래와 같습니다.

useEffect(() => {
  if(!nickname){
  	Router.replace('/login');
  }
}, [nickname]);

if문을 통해 해당 state 값이 없으면 Router.replace를 통해 login 페이지로 리다이렉션시켜줍니다.

여기서 Router.push를 이용하지 않고 replace를 이용한 것은 history를 남기지 않아 뒤로가기 버튼을 동작하지 않게 만들기 위함입니다.

 

저는 state 값으로 nickname을 사용했는데, 로그인에 관련 된 state값이면 되겠죠? 뭐 id나 useInfo등등

마지막 인자로 [ nickname ] 을 적어주면됩니다.

nickname state가 수정되면 useEffect가 다시 실행됩니다.

 

 

이렇게하면 index에 접근했을때 /login 페이지로 리다이렉트 됩니다.!!

짱간단^^

 

 

 

이번 작업은 배터리 만들기입니다.

핸드폰들 보면 몇 % 남았는지 보이는 것있쬬?

기능은 약간 다르지만 흉내내보겠습니다.

 

제가 원하는 기능은 하루를 기준으로 시, 분을 통해 얼마나 지났는 지를 체크하는 것입니다.

즉 24시가 되면 100%, 오후 12시면 50% 겠죠? 로직을 수정하면 거꾸로도 할 수 있겠죠?

(지금 중요한건 이런 기능에 대한 설명은 아니니깐요.)

 

제로초님 강의에서는 moment를 사용해서 날짜를 구해 사용했는데요,

잠깐 다른 라이브러리에 대해서도 설명해주십니다.

그 중 구글 트렌드를 보시고 요즘 많이 사용한다는 dayjs에 대해 간단한 소개를 해주시는데요.

용량이 가볍기 때문에 많이들 쓴다고 합니다.

저는 dayjs를 통해 만들어보겠습니다.

(사실 moment나 dayjs나 문서보면 비슷비슷한 듯 싶습니다.)

 

찾다보니 moment를 사용해 디지털 시계같은것을 구현한 라이브러리도 있더라구요.ㅎㅎ;

 

moment와 dayjs 대체에 관한 블로그 글

https://john015.netlify.app/moment-js%EB%A5%BC-day-js%EB%A1%9C-%EB%8C%80%EC%B2%B4%ED%95%98%EA%B8%B0

 

dayjs 라이브러리를 써봅쉬다.

https://day.js.org/en/

https://github.com/iamkun/dayjs

 

먼저 install 해주시구요.

npm i dayjs

 

코드는 아래와 같습니다.

뭔가 최적화 시킬 수 있을 것 같기도 한데.

react 공부 중이라 정확히는 아직 잘 모르겠네요.

프로젝트를 더 진행하면서 좋은 수가 떠올르길 바랍니다.ㅠ

import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import dayjs from 'dayjs';

function getCurrentPercent(time){
    const totalMin = 24 * 60;
    const currentMin = (time.format('HH') * 60) + Number(time.format('mm'));
    
    return Math.floor(100 / (totalMin / currentMin));
}

const BatteryWrapper = styled.div`
    &:before {
        margin-right: 3px;
        display: inline-block;
        content: '${props => Math.floor(props.percent)}%';
        color: ${props => props.themecolor};
    }

    .gauge {
        display: inline-block;
        width: 28px;
        height: 12px;
        border: 1px solid ${props => props.themecolor};
        border-radius:3px;
    }

    .gauge:before {
        display: block;
        content: '';
        width: ${props => props.percent}%;
        height: 100%;
        background-color: ${props => props.themecolor};
    }
`;

const Battery = ({ themecolor }) => {
    const [time, setTime] = useState(dayjs());
    const [percent, setPercent] = useState(null);
    let timerInterval = null;

    useEffect(() => {
        timerInterval = setInterval(() => {
            setTime(dayjs());
        }, 1000);

        return () => {
            clearInterval(timerInterval);
        };
    }, []);

    useEffect(() => {
        const currentPer = getCurrentPercent(time);
        
        if(percent === currentPer){
            return;
        }

        setPercent(Math.floor(currentPer));
    }, [time]);

    return(
        <BatteryWrapper themecolor={themecolor} percent={percent}>
            <span className="gauge"></span>
        </BatteryWrapper>
    );
};

Battery.propTypes = {
    themecolor: PropTypes.string,
};

Battery.defaultProps = {
    themecolor: '#333',
};

export default Battery;

 

나중에 할 일인데, 언어를 ko만 가져와서 사용할 수 있도록 설정할 수 있습니다.

(그때쯤 기억나면 추가하도록 할게요)

 

완성 이미지!

배터리 완성 이미지

 

(강의내용과 큰 상관없습니다. 강의 듣고 결과물 만드는 작업 중입니다.)

 

작업물에 wifi 애니메이션이 필요해서 제작해보기로했습니다.

뭐 대충 이런거..

wifi 이미지

 

딱히 기능은 없고 css 애니메이션으로만..

codepen.io에서 간단한 코드를 발견해서 크기만 수정해서 사용하기로 했습니다.

 

감사합니다 ㅎㅎ

코드 출처입니다.

https://codepen.io/roncallyt/pen/GymuE

 

Wifi signal, pure CSS

Português: Fazendo um sinal de wifi usando somente CSS e animações CSS3 através da regra @keyframes. English: Making a wifi signal using only CSS and ...

codepen.io

 

일단 styled-components를 통해 작업하는데, keyframe을 어떻게 처리할까 하고 찾아보다가 발견했고 참고글을 읽고 작업했습니다^^. 

공식문서에도 있겠지요. 쉽게 설명해주셨습니다.

https://medium.com/@shlee1353/%EB%A6%AC%EC%95%A1%ED%8A%B8-styled-components-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98-%EA%B5%AC%ED%98%84-fbbb8aa9e722

 

리액트 styled components 애니메이션 구현

웹에서 애니메이션을 구현할 때 transition과 animation을 사용합니다. transition은 엘리먼트의 상태변화에 쉽게 사용할 수 있으며, 정해진 시작점과 종료점을 가지고 있습니다. 예로, hover 상태시 엘리

medium.com

공식문서도 확인해봅시다.

styled-components.com/docs/basics#animations

 

styled-components: Basics

Get Started with styled-components basics.

styled-components.com

 

별도로 keyframes를 제공해줍니다.

import styled, { keyframes } from 'styled-components';

 

이건 완성 코드!

import React from 'react';
import PropTypes from 'prop-types';
import styled, { keyframes } from 'styled-components';

const lineDefaultStyle = `
    border: 2px solid transparent;
    border-radius: 100%;
`;

const appearIn = (themeColor) => keyframes`
    0%{ border-top-color: transparent; }
    25%{ border-top-color: ${themeColor}; }
    75%{ border-top-color: ${themeColor}; }
    100%{ border-top-color: ${themeColor}; }
`;

const appearMiddle = (themeColor) => keyframes`
    0%{ border-top-color: transparent; }
    25%{ border-top-color: transparent; }
    75%{ border-top-color: ${themeColor}; }
    100%{ border-top-color: ${themeColor}; }
`;

const appearOut = (themeColor) => keyframes`
    0%{ border-top-color: transparent; }
    25%{ border-top-color: transparent; }
    75%{ border-top-color: transparent; }
    100%{ border-top-color: ${themeColor}; }
`;

const OutLine = styled.div`
    ${lineDefaultStyle}
    margin: 1px auto;
    width: 25px;
    height: 30px;
    border-top-color: ${props => props.themeColor};
    animation: ${props => appearOut(props.themeColor)} 1.5s infinite linear
`;

const MiddleLine = styled.div`
    ${lineDefaultStyle}
    margin: 1px auto;
    width: 18px;
    height: 25px;
    border-top-color: ${props => props.themeColor};
    animation: ${props => appearMiddle(props.themeColor)} 1.5s infinite linear
`;

const InLine = styled.div`
    ${lineDefaultStyle}
    margin: 1px auto;
    width: 14px;
    height: 23px;
    border-top-color: ${props => props.themeColor};
    animation: ${props => appearIn(props.themeColor)} 1.5s infinite linear
`;

const Dot = styled.div`
    ${lineDefaultStyle}
    margin: 2px auto;
    width: 3px;
    height: 3px;
    border: 0;
    background: ${props => props.themeColor};
`;

const Wifi = (({ themeColor }) => {
    return(
        <OutLine themeColor={themeColor}>
            <MiddleLine themeColor={themeColor}>
                <InLine themeColor={themeColor}>
                    <Dot themeColor={themeColor} />
                </InLine>
            </MiddleLine>
        </OutLine>
    );
});

Wifi.propTypes = {
    themeColor: PropTypes.string,
};

Wifi.defaultProps = {
    themeColor: '#333',
};

export default Wifi;

테마색으로 라인을 그려주려고 외부에서 props를 전달받습니다.

뭔가 중복되는 코드들을 줄일 수 있을 것 같은데, 최적화는 추후에..^^;;

 

완성된 와이파이!

wifi

근데 왜 노트북에서는 잘 되던게, 데탑오니까 애니메이션 반복이 안되는지는 봐야겠습니다~

infinite가 빠졌군요. ㅎ 코드는 수정해두었습니다.~

 

여튼 약간 엉성하긴 한데, 좋습니다. 굿굿

 

 

+ Recent posts