로딩바, 진행바.
출처 : https://www.invisionapp.com/inside-design/progress-bar/
TED내용인데 프로그레스바가 사용자의 행복에 영향을 끼친다는 연구결과다. 정확성은 상관없다고 한다 ㅎㅎ
Slider컴포넌트와 거의 흡사해서 다 올리진 않겠다.
대신 신기한 스타일을 가져와봄
background-size: 10px;
background-image: linear-gradient(
45deg,
rgba(255, 255, 255, 0.15) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, 0.15) 50%,
rgba(255, 255, 255, 0.15) 75%,
transparent 75%,
transparent 100%
);
animation: move 1000ms linear infinite;
@keyframes move {
from {
background-position: 0 0;
}
to {
background-position: 40px 0;
}
}
이렇게 하면 프로그레스바가 움직이는것처럼 보이게 된다.
움짤을 따와야하나..?
텍스트 사이에 선을 말하는 것!
내가 만들었던 CrossLine
컴포넌트와 흡사하다!
const Divider = ({ type = "horizontal", size = 8, ...props }) => {
const dividerStyle = {
margin: type === "vertical" ? `0 ${size}px` : `${size}px 0`,
};
return (
<Line
{...props}
className={type}
style={{ dividerStyle, ...props.style }}
/>
);
};
<hr>
태그가 뭔지 몰랐는데, 수평 가로선을 의미하는 시멘틱 태그가 존재했다.
항상 잘 알고써야지...
상태가 업데이트되기 전에 보여주는 UI
출처:https://www.whitespectre.com/ideas/skeleton-screens-for-a-better-loading-experience-in-react/
이런걸 생각하면 된다. 핵심은 styledComponent로 잘게 쪼갠 뒤, 모양에 맞게 사용하는 것이다.
//Base
const Base = styled.div`
display: inline-block;
border-radius: 4px;
background-image: linear-gradient(
98deg,
#dfe3e8 0px,
#efefef 40px,
#dfe3e8 80px
);
background-size: 200% 100%;
background-position: 0 center;
`;
//Box
const Box = styled(Base)`
width: ${({ width }) => (typeof width === "number" ? `${width}px` : width)};
height: ${({ height }) =>
typeof height === "number" ? `${height}px` : height};
`;
만약 원형 스켈레톤UI가 필요하다면, 너비-높이를 통일 후 border-radius만 50%주면 되겠지?
아~주 자주 사용하는 Input컴포넌트를 재사용 가능하게 만들어보자. 보통 label
로 많이 감싸서 사용한다.
이번에도 스타일은 제외!
<Wrapper {...wrapperProps}>
<Label>{label}</Label>
<StyledInput
invalid={invalid}
required={required}
readOnly={readOnly}
disabled={disabled}
{...props}
/>
</Wrapper>
별거 없구만!
사소한 의문점은 하나있다. HTML속성들은 대부분 카멜케이스를 지키지 않고 소문자로 작성하는데 왜 readOnly
만 카멜케이스인가?
=> 생각해보니 html이 아니라 jsx구나...바보네?
select
태그를 이용한 컴포넌트. 참고로 placeholder
는 options
중 하나를 hidden
으로 만들어 사용한다.
const formattedData = data.map((item) =>
typeof item === "string" ? { label: item, value: item } : item
);
const options = formattedData.map((item) => (
<options key={item.value} value={item.value}>
{item.label}
</options>
));
if (placeholder) {
options.unshift(
<options key="placeholder" value="" hidden>
{placeholder}
</options>
);
}
return (
<Wrapper block={block} {...wrapperProps}>
<Label>{label}</Label>
<StyledSelect
invalid={invalid}
required={required}
disabled={disabled}
{...props}
>
{options}
</StyledSelect>
</Wrapper>
Flux는 디자인패턴만 들어봤는데, 무슨 컴포넌트인고 하니 flex
를 이용하여 가로-세로 레이아웃을 컴포넌트 단위로 추상화 해놓은거다. grid
와 기능이 비슷해보이는데, 아마 지원되지 않는 브라우저를 위해서 사용하는걸까?
클래스를 이용하면 간단하지만, 컴포넌트로 만들면 좀 더 확장성이 좋은게 장점인듯하다.
생각보다 코드가 더 길어져서 최대한 함축해보겠음..
//Row.js
const AlignToCSSValue = {
top: "flex-start",
middle: "center",
bottom: "flex-end",
};
const StyleRow = styled.div`
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
justify-content: ${({ justify }) => justify};
align-items: ${({ align }) => AlignToCSSValue[align]};
`;
const Row = ({ children, justify, align, gutter, ...props }) => {
return (
<StyleRow {...props} align={align} justify={justify}>
{children}
</StyleRow>
);
};
//Col.js
const StyleCol = styled.div`
max-width: 100%fit-content;
box-sizing: border-box;
width: ${({ span }) => span && `${(span / 12) * 100}%`};
margin: ${({ offset }) => offset && `${(offset / 12) * 100}%`};
`;
const Col = ({ children, span, offset, ...props }) => {
return (
<StyleCol {...props} span={span} offset={offset}>
{children}
</StyleCol>
);
};
Row
내부에 gap
을 주고싶으면 contextAPI
를 이용하여 값을 공유해서 Row
에게만 할당하여 사용하는게 편하다. Col
에 하나씩 줄 필요가 없으니까.
다만 고민되는점은 Row
컴포넌트 내부 너비를 초과해서 Col
컴포넌트를 렌더링하면 줄이 바뀐다. 코드를 읽을때 하나의 Row
에 20개의 Col
이존재한다면 분명 20개의 열이 있을거라고 볼텐데...예측하지 못한 동작이 아닐까?물론 일부러 줄바꿈 되라고 flex-wrap
을 사용하셨다.
다만 줄바꿈이 된다면 Row
를 하나 더 사용해야되지 않을까...
나머지 2개는 잘 모르는부분이없어서 숙지만 해뒀다..!
컴포넌트를 굉장히 작은 단위로 잘 쪼개시고 특히 합성 기법을 잘 사용하셔서 좋았다. 재사용 가능한 컴포넌트가 어떤것인지 맛봄! 특히 children
프롭을 이용하여 다루는게 정말 신기했다.
다만 프롭스의 갯수가 좀 많은점등은 고민이다. Select컴포넌트의 options도 아예 합성컴포넌트로 쪼개서 하신 것들 처럼 Selec.option
이렇게 사용해보면 좋을것 같기도?ㅎㅎ