createContext를 사용하여 provider, context 생성
Toc.js 생성
메뉴에서 이동 시킬 위치를 각각의 컴포넌트에서 pos로 받아와서 저장 시킬 예정
import React from "react";
import { createContext, useState } from "react";
const ToCContext = createContext([{}, () => {}]);
const TocProvider = ({ children }) => {
const [pos, setPos] = useState({
First: 0,
Second: 0,
Third: 0,
Fourth: 0,
});
return (
<ToCContext.Provider value={[pos, setPos]}>{children}</ToCContext.Provider>
);
};
const { Consumer: ToCConsumer } = ToCContext;
export { TocProvider, ToCConsumer };
export default ToCContext;
페이지의 위치 pos에 저장시키기
먼저, context를 사용하려는 컴포넌트 바깥에서 Provider로 감싸준다.
import logo from "./logo.svg";
import "./App.css";
import Nav from "./Nav";
import First from "./First";
import Second from "./Second";
import Third from "./Third";
import Fourth from "./Fourth";
import { TocProvider } from "./Toc";
import styled from "styled-components";
const BodyStyle = styled.div``;
function App() {
return (
<div className="App">
<TocProvider>
<Nav />
<BodyStyle>
<First />
<Second />
<Third />
<Fourth />
</BodyStyle>
</TocProvider>
</div>
);
}
export default App;
ToC.js에서 생성한 ToCContext의 pos를 useContext로 불러옴
useRef를 이용해서 컴포넌트 First의 ref값을 가져옴
해당 컴포넌트의 절대값을 구하기위해 Viewport의 시작지점을 기준으로 한 상대 좌표인 element.getBoundingClientRect(). top과 window.pageYOffset 전체 페이지에서 얼만큼 scroll 됐는지 픽셀 단위를 알려주는 값을 더 함
import React, { useContext, useEffect, useRef } from "react";
import styled from "styled-components";
import ToCContext from "./Toc";
const FirstStyle = styled.div`
width: 100%;
height: 500px;
background-color: green;
`;
function First() {
const element = useRef(null);
const [pos, setPos] = useContext(ToCContext);
useEffect(() => {
const rect = element.current.getBoundingClientRect();
setPos((pos) => ({
...pos,
[element.current.id]: rect.top + window.pageYOffset,
}));
}, [setPos]);
return (
<FirstStyle id="First" ref={element}>
first
</FirstStyle>
);
}
export default First;
네비게이션 구현
useEffect로 현재 스크롤 위치가 메뉴에 해당하는 컴포넌트 영역에 들어왔는지 체크 하고 들어오면 메뉴 폰트에 bold를 줌
import React, { useContext, useEffect, useState } from "react";
import styled from "styled-components";
import ToCContext from "../../../components/ToC";
const NavFont = styled.a`
font-family: Noto Sans KR;
font-weight: ${(props) => props.active};
font-size: 2.2rem;
color: #ffffff;
line-height: 3.2rem;
text-decoration: none;
`;
function Header({
list = [
{
name: "First",
href: "First",
},
{
name: "Second",
href: "Second",
},
{
name: "Third",
href: "Third",
},
{
name: "Fourth",
href: "Fourth",
},
],
}) {
const [active, setActive] = useState(0);
const [pos] = useContext(ToCContext);
useEffect(() => {
const onScroll = () => {
const scrollTop = window.pageYOffset;
if (scrollTop < pos.Second) {
setActive(0);
}
if (pos.Second <= scrollTop && scrollTop < pos.Third) {
setActive(1);
}
if (pos.Third <= scrollTop && scrollTop < pos.Fourth) {
setActive(2);
}
if (pos.Fourth <= scrollTop) {
setActive(3);
}
};
if (pos.Second !== 0 && pos.Thrid !== 0 && pos.Fourth !== 0) {
window.addEventListener("scroll", onScroll);
}
console.log("active", active);
return () => {
window.removeEventListener("scroll", onScroll);
};
}, [pos]);
return (
<Box>
<NavBox>
{list.map((el, idx) => (
<NavFont
key={idx}
href={`#${el.href}`}
active={idx === active ? "bold" : "regular"}
>
{el.name}
</NavFont>
))}
</NavBox>
</Box>
);
}
export default Header;
728x90
'Usage > ReactJS' 카테고리의 다른 글
React Slick,Styled-components를 활용하여 현재 슬라이드에 border 주기 (0) | 2021.03.22 |
---|---|
스크롤할때 특정 컴포넌트 영역에 들어가면 나타나는 요소 구현 (0) | 2021.03.21 |
React Tab Menu 구현 (0) | 2021.03.18 |