banner 따라만들기 - 01

Song-Minhyung·2022년 7월 14일
0

preCrew이야기

목록 보기
3/12
post-thumbnail

서론

처음에는 넷이서 위의 링크의 페이지를 똑같이 만들기로 했다.
하지만 한명이 나가게 됐고 세명에서 만들게 되었따.

7월10일 저녁에 구글밋으로 회의를 해서 banner를 만들기로 했다.

제일 처음 작업할건 저곳에 들어가는 최소한의 공통 컴포넌트의 개발이다.
종류는 Button, Name, ColorPicker, InputNumber 이 있다.

여기서 나는 ColorPicker와 전체적인 레이아웃을 담당했다.
레이아웃은 Header, Content, Banner, Controls를 나눠서 개발했으며
ColorPicker는 React-Color 라이브러리를 사용해 간단하게 개발했다.

레이아웃 작성

전에는 컴포넌트를 개발하면 그 안에 mvc를 모두 때려박았었다.
그리고 이렇게 개발한 컴포넌트들은 모두 components 폴더에 때려 박았었다.

근데 이렇게 하니 나중에 어떤 컴포넌트가 어디서 어떻게 작동하는지 파악하는데 시간이 걸렸고,
컴포넌트를 찾아도 주석만 읽고 과거의 내가 어떻게 코드를 짰는지 파악하는데도 시간이 걸렸다.

그래서 이번에는 조금 다르게 접근했다.

컴포넌트 이름은 폴더로 구분하고 그 안에 index.tsx, style.ts를 생성했다.
스타일과 비즈니스 로직 부분을 나눠주니 코드가 훨씬 읽기 좋아졌다.

이런식으로 말이다.


components
├── Content
│   ├── Banner
│   │   ├── index.tsx
│   │   └── style.ts
│   ├── Controls
│   │   ├── ColorPicker
│   │   │   ├── index.tsx
│   │   │   └── style.ts
│   │   ├── index.tsx
│   │   └── style.ts
│   ├── index.tsx
│   └── style.ts
└── Header
	├── index.tsx
    └── style.ts

폴더로 컴포넌트를 구분해줬기 떄문에 더 명확해졌다.
하지만 이 방법의 단점은 아직 모르겠다.
다른 프로젝트에도 적용해봐야 어떤 단점이 있는지 알것같다.

그렇게 해서 아래와 같은 결과가 나왔다.
dev
원래 페이지는 이렇다.
origin
두개를 비교해보면 상당히 비슷하게 작성했다.

코드는 여기에서 볼 수 있다.

컬러피커 작성

color picker 는 아래와 같은 기능을 한다.

  1. 트리거를 누르면 컬러피커가 나타난다.
    1-1. 컬러피커가 눌렸을 떄 트리거를 다시 누르면 컬러피커가 사라진다.
    1-2. 컬러피커가 눌렸을 때 트리거 외의 다른곳을 누르면 컬러피커가 사라진다.
  2. 색상을 고르면 해당 색이 컬러피커에도 적용된다.
    2-1. props로 전달된 대상의 색상도 바뀐다.

위의 기능을 아래의 코드로 구현해봤다.

// ColorPicker/index.tsx

import React, { useRef, useState } from 'react';
import ColorPickerBlock, { Picker, PickerCircle } from './style'
import {SketchPicker, ColorResult} from 'react-color';
import { useAppDispatch, useAppSelector } from '../../../../store/hooks';
import { changeBackgroundColor, changeBorderColor, changeForegroundColor } from '../../../../store/optionSlice';
import useOutsideDetect from '../../../../hooks/useOutsideClick';

interface ColorPickerProps {
    whosColorChange: 'backgroundColor' | 'foregroundColor' | 'borderColor';
    changeColorFunction: 
        | typeof changeBackgroundColor
        | typeof changeForegroundColor
        | typeof changeBorderColor;
}

const ColorPicker = ({
    whosColorChange,
    changeColorFunction
}:ColorPickerProps) => {
    const color =  useAppSelector(state=>state.option[whosColorChange]);
    const dispatch = useAppDispatch();

    const [isClick, setIsClick] = useState(false);
    const circleRef = useRef<HTMLDivElement>(null);
    
    useOutsideDetect(circleRef, () => {
        setIsClick(false);
    });
    

    const handleChangePicker = (color: ColorResult) => {
        dispatch(changeColorFunction(color.hex));
    };
    const handleClickPickerCircle = () => {
        setIsClick(!isClick);
    }

    return (
        <ColorPickerBlock>
            <PickerCircle 
                color={color}
                onClick={handleClickPickerCircle}
                ref={circleRef}
            >
                {isClick && 
                    <Picker>
                        <SketchPicker
                            color={color}
                            onChange={handleChangePicker}
                        />
                    </Picker>
                }
            </PickerCircle>
        </ColorPickerBlock>
    );
}

export default ColorPicker;
// ColorPicker/style.ts

import styled, { css } from "styled-components";
import {darken} from 'polished'

interface TPickerCircle {
    color: string;
}

export default styled.div`
    width: 100%;
    height: 100%;
    position: relative;
    z-index: 100;
`;

export const PickerCircle = styled.div<TPickerCircle>`
    width: 40px;
    height: 40px;
    border-radius: 50%;
    
    ${({color}) => css`
        background: ${color};
        border: 3px solid ${darken(0.2, color)};
    `};

    cursor: pointer;
`;

export const Picker = styled.div`
    position: absolute;
    left: -220px;
    top: 20px;
`;

코드를 살펴보면 우선 propswhosColorChange, changeColorFunction를 받는다.
whosColorChange는 store에서 어떤 대상의 색상을 바꿀지 선택하기위해 받아왔다.
그래서 이런식으로 값을 받아오고

const color =  useAppSelector(state=>state.option[whosColorChange]);

dispatch는 이런식으로 해줬다.

// 컬러피커의 색상을 골랐을 때 호출되는 함수.
const handleChangePicker = (color: ColorResult) => {
        dispatch(changeColorFunction(color.hex));
    };

useAppSelector, useAppDispath

위의 코드를 보면 useSelector, useDispatch가 아니라
useAppSelector, useAppDispath를 쓴걸 볼 수 있다.

이렇게 쓴 이유는 사전에 모든 타입에 대해 선언해두고 편하게 쓰기 위해서 이렇게 했다.

// reduxStore.ts
import { configureStore } from '@reduxjs/toolkit';
import optionReducer from './optionSlice'

export const store = configureStore({
    reducer: {
        option: optionReducer,
    }, 
    // middleware: [thunk],
    devTools: true
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
// hooks.ts
import { useSelector } from "react-redux";
import { TypedUseSelectorHook, useDispatch } from "react-redux";
import { AppDispatch, RootState } from "./reduxStore";

export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

요롷게 말이다.

ColorPicker 완성

useEffect()를 사용해 랜덤한 값을 넣어준후
ColorPicker에 props를 넣어주기만 하면 간단하게 사용할 수 있다.

import React, { useEffect } from 'react';
import styled from 'styled-components';
import ColorPicker from './components/Content/Controls/ColorPicker';
import { useAppDispatch } from './store/hooks';
import { changeBackgroundColor } from './store/optionSlice';
import { getRandomColor } from './utils/colorUtil';

const App = () => {
  const dispatch = useAppDispatch();

  useEffect(()=>{
    const randomColor = getRandomColor();
    dispatch(changeBackgroundColor(randomColor));
  },[])
  return (
    <Test>
      <ColorPicker
        whosColorChange={'backgroundColor'}
        changeColorFunction={changeBackgroundColor}
      />
    </Test>
  );
};

export default App;

const Test = styled.div``;

결과는 이렇다.
colorPicker

향후 방향

이제 이렇게 만든 컴포넌트들을 조합해 더 큰 컴포넌트를 만들 일만 남았다.
오늘 저녁에 어떻게 만들지 회의 후 다시 만들게 될것같다.
끗.

profile
기록하는 블로그

0개의 댓글

관련 채용 정보