SEB 섹션2. 18일차 TIL - React 컴포넌트 디자인(2)
Styled-Component
작성 기본
const ComponentA = styled.div`
padding-top: 10px;
color: black;
font-size: 1em;
text-align: center;
`;
위 코드와 같이 기존에 컴포넌트를 구성할 때 함수와 같은 형태가 아닌 방식으로 구현이 가능하다. 이와 같이 작성 후 render가 이루어지는 함수 컴포넌트의 return 문 안쪽 등에 컴포넌트를 삽입 시 정상적으로 하위 컴포넌트의 역할을 하는 것을 확인할 수 있음
[도식화]
const [컴포넌트명] = styled.[html태그]`
// 리터럴 템플릿 안에서 css 속성 기입
// ex) color: black;
`
도식화된 내용과 같은 방식으로 작성을 하게되면 새롭게 생겨난 컴포넌트는 리터럴 템플릿 안에서 기재한 스타일 속성을 반영한 컴포넌트로 생성되게 된다. 위의 리터럴 템플릿은 엄밀하게는 Tagged templates를 활용한 것인데 이는 템플릿 리터럴을 함수로 파싱 할 수 있게 하는 기능을 가진다.
그리고 주의하여야할 점은 styled-component를 정의할 때는 render 메소드 밖에서 이루어져야 한다.
이와 같이 사용되어야 하는 이유는 styled-component가 리턴문 안에서 정의되면 컴포넌트가 리렌더링 될 때마다 스타일 속성을 지닌 컴포넌트가 매번 새로 정의되고, 이는 렌더링 속도 저하에 영향을 미치기 때문이다.
props 활용
import styled from "styled-components";
// Styled Component
const Input = styled.input`
padding: 0.5em;
margin: 0.5em;
color: ${(props) => props.inputColor || "red"};
background: papayawhip;
`;
// App component
export default function App() {
return (
<div>
{/* 아래 Input 컴포넌트는 styled component인 Input 컴포넌트에 지정된 inputColor(red)가 적용되었습니다. */}
<Input defaultValue="input-A" type="text" />
{/* 아래 Input 컴포넌트는 props로 전달된 커스텀 inputColor(blue)가 적용되었습니다. */}
<Input defaultValue="input-B" type="text" inputColor="blue" />
</div>
);
}
styled component에는 기존에 함수형 컴포넌트에서 활용하는 것과 동일한 방식으로 props를 전달하여 이를 통해 스타일을 변경하는 등의 조건 등을 설정해줄 수 있다.
셀렉터 활용
const Thing = styled.div`
color: blue;
&:hover {
color: red; // <Thing> when hovered
}
& ~ & {
background: tomato; // <Thing> as a sibling of <Thing>, but maybe not directly next to it
}
& + & {
background: lime; // <Thing> next to <Thing>
}
&.apple {
background: orange; // <Thing> tagged with an additional CSS class ".apple"
}
.banana & {
border: 1px solid; // <Thing> inside another element labeled ".banana"
}
.blueberry {
background-color: yellow; // an element labeled ".blueberry" inside <Thing> without ampersand(&)
}
`;
위와 같은 방식으로 종속되는 클래스에 대한 스타일 및 기존 CSS에서 활용하던 셀렉터를 활용할 수가 있다.
useRef
리액트에서 제공되는 hook의 하나로 기본적으로 사용되는 경우는 DOM 엘리먼트에 대한 접근 및 조작이 필요한 경우에 활용된다. useRef를 통해서 확보된 대상 DOM 객체는 컴포넌트의 전체 생애주기(Lifetime) 동안 유지된다.
리액트 내에서 DOM API로 조작을 하는 경우
아직까지 개인적으로 크게 그런 상황에 부딪힌 적은 없지만 리액트로 코드를 작성하는데 DOM에 대한 접근이 필요한 순간이 발생될 수 있다. 그렇지만 리액트에서는 DOM API 사용을 권장하지 않고 있다.
[DOM API를 사용하려는 경우]
1. 일단 리액트 만드신 분들께서 하지 말라고 했다.
2. 원하는 대로 작성 내용이 적용되지 않을 가능성이 있다.
3. React는 DOM에 직접 접근하는 것을 가정하지 않고, 내부 작업으로 해결하는 것을 가정하고 있다.
그런데도 리액트로 코드 작성을 하다가 DOM에 대한 접근이 필요하다면 useRef를 사용하여야 한다.
사용 예시
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
* 리액트 API Reference의 useRef 예시 코드이다.
1. 우선 useRef를 선언하면서 초기 값을 'null'로 잡아준다.
2. 가져오고 싶은 DOM Element를 구성할 렌더링 엘리먼트에 ref 속성과 선언한 useRef 함수를 속성 값으로 넣어준다.
이렇게 되면 ref속성을 부여한 DOM Element로 접근 및 조작이 가능하다. 이 때 DOM Element는 useRef의 current에 담겨져있다. 공식문서에서도 설명이 되어 있지만 위 코드의 inputEl은 객체 형태이며, 풀어보면 아래와 같다.
{current : ...DOM node}
따라서 inputEl.current로 하였을 때 실질적으로 해당 DOM 엘리먼트에 접근이 가능하며 조작을 시도 할 수 있다.