웹 디자인 업계(?)에서 많이 사용되는 스타일링 도구로 bootstrap이라는 것이 있다.

 

>> 참조: getbootstrap.com/docs/5.0/getting-started/introduction/

 

Introduction

Get started with Bootstrap, the world’s most popular framework for building responsive, mobile-first sites, with jsDelivr and a template starter page.

getbootstrap.com

반응형 웹과 모바일 환경을 동시에 만족시켜 주는 CSS 스타일링 도구로, 사전 정의된 색상에서부터 크기, 아이콘 등을 풍부하게 제공하고 있어 그대로 가져다 쓰거나 또는 약간의 커스터마이징을 해서 쓰는 방식으로 수많은 웹 디자이너들이 사용하고 있다. 심지어는 Visual Studio에서도 기본 템플릿에 포함시켜 둘 정도니 더 할 말이 없을 정도. (예를 들면 primary, secondary, success, danger, warning, info 등의 색상 클래스명 및 lg, md, sm, xs 등의 크기 클래스명을 제공해서 이 클래스명들만 잘 사용하면 그럴 듯한 UI를 만들 수 있다.) 단, 이 모든 걸 다 외우려면 어렵다. 배우기 어려워서가 아니라 너무 많고 방대하니까. 기본 사용법 정도만 학습한 다음 위 사이트를 즐겨찾기 해 두고 필요할 때 틈틈이 찾는 방식이 유용할 듯.

 

이 bootstrap을 React와 결합시켜놓은 reactstrap이라는 컴포넌트가 있다. 버튼, 탭, 폼 등 bootstrap의 사전 정의된 스타일들을 컴포넌트 형태로 만들어놓아 쉽게 컴포넌트 형태로 가져다 쓸 수 있게 만들어 놓은 것인데... 처음에는 좀 빡세게 공부해야 된다. 어떤 컴포넌트가 어떤 기능(?)을 하는지 다 알아야 하니까. 이것 역시 아래 사이트를 즐겨찾기 해 두고 필요할 때 틈틈이 찾아서 써도 되긴 할 것 같다.

 

>> 참조: reactstrap.github.io/

 

reactstrap - React Bootstrap 4 components

Installation NPM Install reactstrap and peer dependencies via NPM npm install --save reactstrap react react-dom Import the components you need Danger! import React from 'react'; import { Button } from 'reactstrap'; export default (props) => { return ( Dang

reactstrap.github.io

 

이 밖에도 좀 원시적인 방식이지만, styled-components라는, 일일이 스타일을 작성해서 원하는 스타일이 적용된 컴포넌트를 만들 수 있는 컴포넌트가 있는데, 버튼, 탭, 폼 등의 기본 요소들을 직접 다 스타일링해서 컴포넌트 라이브러리를 만들려고 할 때 정도에는 유용하겠지만 글쎄... 실제로 얼마나 유용할 지는 살짝 미지수. 위 reactstrap과 결합해서 사용할 수 있다면 엄청난 시너지 효과가 날 것 같은데, 그게 가능할 지는 모르겠다.

 

 

 

아무튼, reactstrap으로 돌아와서,

위 사이트에서 컴포넌트 예제를 하나하나 확인하다 막판에 의문이 든 내용이 하나 있는데,

 

 

>> 참조: reactstrap - Tooltips

 

reactstrap - Tooltips

Tooltips Tooltips are built with https://popper.js.org/ via https://github.com/souporserious/react-popper. Somewhere in here is a tooltip. /* eslint react/no-multi-comp: 0, react/prop-types: 0 */ import React, { useState } from 'react'; import { Tooltip }

reactstrap.github.io

 

위 URL을 보면 맨 아래 예제인 UncontrolledTooltip에서 scheduleUpdate( ) 함수를 이용해 2초마다 툴팁 내용을 자동으로 갱신하는 내용이 있다. 여기서 React 16.8에서 추가된 useEffect( ) Hook 함수도 만나게 되고... 그래서 예상치 않게 공부를 좀 더 해야 했는데...

 

그런데, 자세히 들여다 보면 뭔가 좀 이해가 안되는 부분이 있다.

 

<UncontrolledTooltip placement="top" target="ScheduleUpdateTooltip" trigger="click">
{({ scheduleUpdate }) => (
	<TooltipContent scheduleUpdate={scheduleUpdate} />
)}
</UncontrolledTooltip>

 

이 부분에서, scheduleUpdate가 무려 세 번이나 쓰이고 있는데, 두 번째 scheduleUpdate는 TooltipContext 컴포넌트에 props로 전달하는 것이므로 그렇다 치고, 첫 번째와 세 번째 scheduleUpdate는 대체 어디에서 나온 녀석일까? Visual Studio 편집기에서 위 코드 부분에 마우스를 올려 보면 IntelliSense가 동작해서 var scheduleUpdate: () => void라며 툴팁이 뜨는데, 함수란다. 대체 이 정보는 어디에서 나온 것일까?

 

위 코드를 아래와 같이 고쳐보면 당장 알 수 있다.

 

<UncontrolledTooltip placement="top" target="ScheduleUpdateTooltip" trigger="click">
{({ scheduleUpdate2 }) => (
	<TooltipContent scheduleUpdate={scheduleUpdate2} />
)}
</UncontrolledTooltip>

 

이렇게 수정하고 실행해 보면, 잠시 되는 것처럼 보이다가... 에러가 발생한다. scheduleUpdate2 함수가 정의되지 않았다면서. 마우스를 올려 봐도 그냥 any란다. 함수라는 정보가 나오지 않는다.

 

그렇다면 scheduleUpdate라는 함수 이름은 어딘가에서 정의되어 있으므로 고쳐쓸 수 없다는 건데... 예제 코드 내에서는 찾아볼 수 없다. 즉, 사용하는 코드가 아니라 import한 UncontrolledTooltip 컴포넌트 내부 어딘가에 명시적으로 정의가 되어 있다는 것.

 

여기서부터 잠시 뻘짓 퍼레이드...

 

node_modules 폴더를 뒤져서 reactstrap의 src를 열어보면 UncontrolledTooltip.js 파일이 있다. 거기에도 없었다.

 

UncontrolledTooltip은 Tooltip을 import해서 쓰고 있으므로 Tooltip.js 파일을 열어 봤다. 거기에도 없었다. (어쨌거나 하나 더 건진 수확은... Tooltip 컴포넌트에서도 scheduleUpdate 함수를 쓸 수 있는 것이라는 사실.)

 

Tooltip은 TooltipPopoverWrapper를 import해서 쓰고 있으므로 TooltipPopoverWrapper.js 파일을 열어 봤다. 아... 이제야 뭔가 scheduleUpdate가 나오는데... 여기도 역시 PopperContent를 import해서 쓰고 그 children으로 넘겨주는 함수의 파라미터로 scheduleUpdate를 쓰고 있을 뿐이다.

 

PopperContent.js를 열어 봤다. 역시 scheduleUpdate가 나오긴 하는데... 여기도 여전히 그저 ReactPopper의 children으로 넘겨주는 함수의 파라미터로 쓰고 있을 뿐이다.

 

react-popper 외부 컴포넌트로 넘어가서 dist/index.umd.js 파일을 열어봤다. 그제서야 scheduleUpdate 함수 정의가 나온다. 역시 정의가 되어 있어서 바꿀 수 없는 것이었다. 이제야 scheduleUpdate를 헷갈리게 세 번이나 연달아 쓴 이유를 알겠다...

 

 

잠깐, 바꿀 수 없다고?

그럴리가...

 

ES6/ES2015에는 객체 리터럴 프로퍼티 축약 문법이라는 것이 있다.

 

>> 참조: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer

 

Object initializer

Objects can be initialized using new Object(), Object.create(), or using the literal notation (initializer notation). An object initializer is a comma-delimited list of zero or more pairs of property names and associated values of an object, enclosed in c

developer.mozilla.org

 

딱 해당 내용 부분만 정리해 둔 사이트를 보자면,

 

>> 참조: alligator.io/js/object-property-shorthand-es6/

 

Object Property Value Shorthand in JavaScript with ES6

New with ES6 / ES2015, property shorthands allow you to save time with object definition in JavaScript.

alligator.io

 

그랬다.

 

사실 알고 보니 맨 위에 발췌한 예제에서 ({scheduleUpdate}) => (...) 는 사실 원래 ({scheduleUpdate: scheduleUpdate}) => (...) 였던 것이다. 화살표 함수가 아닌 function으로 써 보자면 아래와 같은.

 

function({scheduleUpdate: scheduleUpdate}) { return (...) }

 

그러므로 사용하는 코드에서 축약 문법을 쓰지 않고 원래 문법대로 쓰면 쉽게 변수/함수명을 바꿀 수 있었던 것이었던 거디었떤 거디~어떤~ 것이었다.

 

<UncontrolledTooltip placement="top" target="ScheduleUpdateTooltip" trigger="click">
{({ scheduleUpdate: scheduleUpdate2 }) => (
	<TooltipContent scheduleUpdate={scheduleUpdate2} />
)}
</UncontrolledTooltip>

 

이렇게.

 

전체 예제를 안 헷갈리는 방식으로 다 옮겨 써 보자면 아래와 같이 쓸 수 있다.

 

import React, { useState, useEffect } from 'react';
import { Button, UncontrolledTooltip } from 'reactstrap';

const shortText = 'Hi';
const longText = 'Long tooltip content to test scheduleUpdate';

const TooltipContent = ({ callback }) => {
  const [text, setText] = useState(shortText);

  useEffect(() => {
    const intervalId = setInterval(() => {
      setText(text === shortText ? longText : shortText);
      callback();
    }, 2000);

    return () => clearInterval(intervalId);
  });

  return (
    <>{text}</>
  );
}

const Example = () => {
  return (
    <div className="text-center">
      <Button id="ScheduleUpdateTooltip">Click me</Button>
      <UncontrolledTooltip placement="top" target="ScheduleUpdateTooltip" trigger="click">
        {({ scheduleUpdate: s }) => (
          <TooltipContent callback={s} />
        )}
      </UncontrolledTooltip>
    </div>
  );
}

export default Example;

 

 

 

 

[추가:참고] 여기서, bootstrap의 사전 정의된 색상, 크기 등을 사용하지 않고 사용자 정의 스타일을 적용하고 싶은 경우에는 다음의 둘 중 하나의 방법을 사용하면 된다.

 

1. 별도 custom.css를 만들고 이를 entrypoint인 App.js에서 맨 마지막으로 import한다. 이 custom.css에는 재정의할 bootstrap의 클래스명을 찾아서 쓰고 원하는 스타일로 정의하면 된다. 예를 들어 Button 컴포넌트의 색상 중 primary를 재정의하고 싶은 경우 ".btn-primary" 를 custom.css에다 만들어 넣어주면 된다. (재정의할 클래스명은 node_modes/reactstrap/src 폴더에서 해당 컴포넌트 소스파일을 열어보면 어렵지 않게 찾을 수 있다.)

 

[./custom.css]

.btn-primary {
  color: #fff;
  background-color: #1b6ec2;
  border-color: #1861ac;
}

 

[./App.js]

import React, { Component } from 'react';
import { Route } from 'react-router';
...
...
import './custom.css'

export default class App extends Component {
...
...
...
}

 

 

2. 컴포넌트 태그에 바로 style 속성을 만들어 넣어주면 된다. 여러 번 반복해서 쓰지 않고 한번만 쓸 경우에는 이 방식이 훨씬 편하다. 예를 들어 위 UncontrolledTooltip 예제 코드에서 "Click me" 버튼의 기본 색상은 reactstrap 정의에 따라 회색톤의 "secondary"로 정의되어 있는데, 위 Button만 "secondary"를 무시하고 색상을 파란색 톤의 "#eeeeff"로 바꾸고 싶은 경우 아래와 같이 쓰면 된다.

 

<Button id="ScheduleUpdateTooltip" style={{backgroundColor: "#eeeeff"}}>Click me</Button>

 

 

 

끝.

 

 



Posted by 떼르미
,


자바스크립트를 허용해주세요!
Please Enable JavaScript![ Enable JavaScript ]