CSS in 리액트 - Inline Style
글을 시작하기 전에 넋두리...
며칠 전 나는 간단한(?) 카드를 만드는 미니 프로젝트를 만들었다. 메인 라이브러리로는 평소 자주 사용하던 React를 사용했고, UI 라이브러리는 이뻐서 사용해 보고 싶었지만 기회가 없어 못 사용해봤던 antd를 사용했다. 그리고 다른 언어와 기술들을 조합하여 프로젝트를 완성했다.
사실 antd를 사용했더라도 당연히 내가 구현하고 싶은 방향과 UI/UX가 있기 때문에 CSS를 수정했다. 물론 리액트를 사용하며 inline CSS, *. css 방식, styled components, CSS-in-JS, scss (이건 조금?) 사용해본 경험은 있었지만, 빠르게 구현하자는 생각에 inline CSS를 통해 장바구니 앱을 구현했다.
"그런데 이렇게 구현하면 어떤 일이 일어났지?"
왜 나는 Inline CSS를 사용하면서 왜 그렇게 했는지에 대해 생각하지 않았을까? 분명 처음에 리액트를 배울 때 배웠던거 같긴 한데 말이다. 무심코 사용했지만, 이렇게 사용하는 건 내가 개발자로서 추구하는 방향이 절대 아니다. 순간 너무 한심했지만, 이런 경험을 반복하기 싫어 다시 한번 정리해 본다.
Inline styles 문제가 있을까?
이 글을 읽기 전에 스스로 먼저 위 질문에 대한 답을 해보자.
과연 인라인 스타일을 사용해서 리액트 컴포넌트를 스타일링한다면 문제가 생길까? 생긴다면 뭐가 생길까? 사실 인라인 스타일링 만큼 사용하기 간편한 건 없다. 특히나 UI 라이브러리를 사용하면서 작은 규모의 앱을 만든다면 더더욱 말이다.
그럼에도 불구하고 내가 말하고 싶은건 인라인 스타일을 피해야 한다는 것이다. 이유는 이전글에서 다뤘던 렌더링과 관련이 있다.
아래 예제는 create-react-app으로 만든 키보드 미러링이다. 내가 키보드로 타이핑하는 게 아래에 나타난다.
import React, { useState } from "react";
const ChildComponent = ({ contents }) => {
return (
<div
style={{
color: "blue",
fontWeight: "bold",
marginTop: "0.5rem"
}}
>
{contents}
</div>
);
};
const App = () => {
const [inputData, setInputData] = useState("");
return (
<div style={{ margin: "1rem" }}>
<h1>렌더링 되는걸 보세요</h1>
<input onChange={e => setInputData(e.target.value)} />
<ChildComponent contents={inputData} />
</div>
);
};
export default App;
위에 코드에서 일반 HTML을 작성한거 같지만, 사실 JSX에 따라 작성했다. 그리고 JSX는 React.createElement(...)로 통해 변환되고 모든 속성이 props 객체의 일부가 된다. 그러다 보니 style 부분의 비교는 항상 false가 나올 수밖에 없고({} === {} // false), 다시 렌더링될때마다 스타일 객체가 다시 계산되어 성능이 저하될 수 있다.
// ...
var ChildComponent = function ChildComponent(_ref) {
var contents = _ref.contents;
return _react.default.createElement("div", {
style: {
color: "blue",
fontWeight: "bold",
marginTop: "0.5rem"
}
}, contents);
};
// ...
물론 이거 외에도 Inline CSS를 추천하지 않는 이유는 더 있다.
- CSS 속성의 중복, 재사용성이 떨어진다.
- 의사 클래스, 의사 요소, 미디어 쿼리, 키 프레임 애니메이션 같은 CSS의 기능을 온전하게 활용할 수 없다.
- 앱의 규모가 커질수록 유지/보수가 어렵고 인라인 스타일이 많으면 코드 가독성도 떨어진다.
- 리액트 공식 문서에서도 일반적으로는 추천하지 않는 방법이다.
TLDR;
만약 인라인 스타일을 사용한다면 결과적으로 React.PureComponent나 React.memo()의 이점이 사라진다. 꼭 인라인을 사용해야 한다면(CSS-in-JS 등을 배우기 위한 시간이나 여건이 안된다면), 아래와 같이 코드를 작성하는 것을 추천한다.
// Bad!
const ReactComponent = props => {
return (
<div
style={{
color: "blue",
fontWeight: "bold",
marginTop: "0.5rem"
}}
>
{props}
</div>
);
};
// Good!
const styles = { color: "blue", fontWeight: "bold", marginTop: "0.5rem" };
const ReactComponent = props => {
return <div style={styles}>{props}</div>;
};