토이프로젝트로 MBTI 테스트만드는데 디자인이 이렇게 나왔다.
1. Ref를 통한 ScrollIntoView 메소드
바닐라 자바스크립트에서는 Document에서 직접 DOM를 뽑아서 저 메소드를 사용했었지만, React에서는 useRef를 통해서 저 메소드를 사용해서 ref.current.scrollIntoView() 를 통해서 우리가 원하는 동작을 취할 수 있다.
https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
2. scrollIntoView 파라미터 ( Optional )
1. alignToTop : boolean
- 참(true)인 경우, 해당 요소의 상단이 스크롤 가능한 부모 요소의 가시 영역의 상단에 맞춰집니다. 기본 값으로 scrollIntoViewOptions: {block: "start", inline: "nearest"} 에 해당합니다.
- 거짓(false)인 경우, 해당 요소의 하단이 스크롤 가능한 부모 요소의 가시 영역의 하단에 맞춰집니다. scrollIntoViewOptions: {block: "end", inline: "nearest"}에 해당합니다.
2. scrollIntoViewOptions
- behavior (옵션): 스크롤링이 즉시 발생하는지 또는 부드럽게 애니메이션화되는지 여부를 결정합니다. 이 옵션은 다음 값 중 하나를 가져야 하는 문자열입니다:
smooth: 부드럽게 애니메이션화되는 스크롤링
instant: 한 번에 즉시 스크롤링이 발생
auto: 스크롤 동작은 scroll-behavior의 계산된 값에 따라 결정됩니다.
- block (옵션): 수직 정렬을 정의합니다. start, center, end 또는 nearest 중 하나입니다. 기본값은 start입니다.
- inline (옵션): 수평 정렬을 정의합니다. start, center, end 또는 nearest 중 하나입니다. 기본값은 nearest입니다.
3. ref 동적 할당
방법은 간단하다. 먼저 useRef를 배열로 뽑아주고 map을 뿌림과 동시에 ref에 index통해 하나씩 차곡차곡 넣어주면 된다.
그리고 버튼을 클릭하면 moveToNextQuestion에 다음 인덱스를 전달시켜서 이동하는 것을 볼 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
const Component = () => {
const questionRef = useRef<(HTMLDivElement | null)[]>([]);
const moveToNextQuestion = (index: number) => {
questionRef.current[index]?.scrollIntoView({
behavior: 'smooth',
block: 'center',
});
setCurrentStep(index);
};
return (
<>
{mbtiTest.map((test, index) => (
<Question
ref={(element) => (questionRef.current[index] = element)}
>
<button onClick={() => moveToNextQuestion(index + 1)}>{test.name}</button>
</Question>
))}
<>
)
}
|
cs |
여기까지만해도 일단 구현은 된다. 하지만 뭔가 아쉬웠다. 애니메이션이 이동하기전에 내가 클릭한게 무엇인지 확인을 해야했고, 우리는 앱뷰를 생각하기 때문에 hover를통해서도 할 수 없는 노릇이였다. 그래서 focus에 애니메이션을 줘서 나름 구현을 해보았다.
4. 애니메이션 추가
일단 저 클릭하는 박스에 css를 추가해주었습니다.
&:focus {
animation: blink 1s 1;
}
@keyframes blink {
0%,
20%,
60%,
100% {
border: 2px solid #5344aa;
}
10%,
30% {
border: 2px solid #d9d8dc;
}
}
`;
그리고 이번에 알았지만 onClick대신에 onAnimationEnd라는 이벤트가 있었다.
<Question
isActive={currentStep === index}
ref={(element) => (questionRef.current[index] = element)}
onAnimationEnd={() => moveToNextQuestion(index + 1)}
>
{contents}
</Question>
이렇게 해주면 위에 박스를 클릭하면 focus 애니메이션이 실행되고 애니메이션이 끝나면 onAnimationEnd에 있는 콜백함수를 실행해줍니다.
'Study > React' 카테고리의 다른 글
useEffect 와 useLayoutEffect의 차이 ? (0) | 2023.01.14 |
---|---|
JS와 JSX 사이의 차이는 무엇일까여 ? (0) | 2023.01.13 |
setState의 비동기성을 들어보셨습니까 ? (0) | 2022.12.10 |
Axios (0) | 2022.09.18 |
React - 공식문서 읽어보기4 (0) | 2022.07.17 |