Sticky Effects
position: stickey라는 지정이 있습니다. 지정 요소가 스크롤 위치까지 도달했을 경우, 요소를 화면 위치 고정하는 style 입니다. 이 stickey 입니다만, 브라우저 서포트 상황이 이마이치입니다. 또, 피터와 고정된 타이밍을, javascript 로 파악하는 방법이 없습니다. 오늘은 이 동작을 구현하면서 스크롤 위치에 따라 외부 통지하는 방법을 소개합니다.code: github/
$ yarn 1209


Context API / Provider 구성
오늘도 Context API를 사용합니다. 현재 표시 영역에 들어 있는 Section 의 index 를 current 에 보관 유지합니다. 우선은 형태 첨부 빈 context 를 생성합니다.
components/context.tsimport { createContext, Dispatch, SetStateAction } from 'react'
export const CTX = createContext({} as {
current: number
setCurrent: Dispatch<SetStateAction<number>>
})
그런 다음 useState의 반환 값을 Provider의 초기 값으로 주입합니다. 요 전날과 함께합니다.
components/provider.tsxexport default (props: Props) => {
const [current, setCurrent] = useState(0)
return (
<Provider value={{ current, setCurrent }}>
{props.children}
</Provider>
)
}
App index에서 Provider를 최고층에 설치합니다. count 는 더미 작성용이므로, 신경쓰지 말아 주세요.
components/index.tsxconst count = 5
export default () => (
<Provider>
<Sections count={count} />
<Indicate count={count} />
</Provider>
)
useStickyWrapper
Custom Hooks는 이전 샘플과 거의 다르지 않습니다. 화면내 판정 로직이 다소 달라, 이번은 화면 상부보다 위에 section 상변이 위치하는 경우 「화면내」라고 판정하고 있습니다.
sections/section/useStickyWrapper.tsconst useStickyWrapper = (props: Props) => {
const [state, setState] = useState<State>(...)
const options = useMemo(...)
useEffect(...) // 画面スクロール時処理
useEffect(...) // 画面内判定処理
}
이번에는 wrapper 컴포넌트와 Custom Hooks를 분리하고 있습니다.
components/sections/section/stickyWrapper.tsxexport default (props: Props) => {
const ref = useRef({} as HTMLDivElement)
useStickyWrapper({
ref,
onEnter: props.onEnter,
onLeave: props.onLeave,
throttleInterval: props.throttleInterval
})
return (
<div
className={props.className}
id={props.id}
ref={ref}
>
{props.children}
</div>
)
}
Context 상태 변경 Section
지금까지 준비한 StickyWrapper Component 를 이용해, Section 를 조립합니다. 화면 내외 판정시의 callback props 는, 부모로부터 주입되는 핸들러를 바인드 합니다.
components/sections/section/index.tsxconst View = (props: Props) => (
<StickyWrapper
id={`section${props.index}`}
className={props.className}
onEnter={props.onEnter}
onLeave={props.onLeave}
>
...
</StickyWrapper>
)
다음은 부모 Container입니다. onEnter, onLeave에서 Context current를 업데이트하고 있음을 알 수 있습니다. 동시에, 자신이 화면내에 들어가 있는지 어떤지의 플래그를 useState 로 확보해, 아이 컴퍼넌트에 주입합니다.
components/sections/section/index.tsxexport default (props: ContainerProps) => {
const [isEnter, updateState] = useState(false)
const { setCurrent } = useContext(CTX)
const onEnter = useCallback(() => {
updateState(true)
setCurrent(props.index)
}, [])
const onLeave = useCallback(() => {
updateState(false)
}, [])
return useMemo(
() => (
<StyledView
index={props.index}
title={props.title}
onEnter={onEnter}
onLeave={onLeave}
isEnter={isEnter}
isLast={props.isLast}
isFirst={props.isFirst}
/>
),
[isEnter]
)
}
Indicate
화면 오른쪽에 표시되는 현재 표시입니다. Context 상태를 참조합니다.

components/indicate/item.tsxexport default (props: ContainerProps) => {
const { current } = useContext(CTX)
const isCurrent = useMemo(() => current === props.index, [
current
])
const style = useMemo(
() =>
isCurrent
? {
transform: 'scale(1.5)',
backgroundColor: styles.blue
}
: {
transform: 'scale(1)'
},
[isCurrent]
)
return useMemo(
() => (
<StyledView index={props.index} style={style} />
),
[style]
)
}
여기도 memoize를 사보하지 않고 실시합니다. 시각 효과로는 수수합니다만, 아이디어 나름으로 여러가지 기능에 응용할 수 있을 것 같습니다.
components/indicate/item.tsxconst StyledView = styled(View)`...`
components/indicate/item.tsxconst View = (props: Props) => (
<span className={props.className} style={props.style} />
)
Reference
이 문제에 관하여(Sticky Effects), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/Takepepe/items/96229b1c676160dd195c
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
import { createContext, Dispatch, SetStateAction } from 'react'
export const CTX = createContext({} as {
current: number
setCurrent: Dispatch<SetStateAction<number>>
})
export default (props: Props) => {
const [current, setCurrent] = useState(0)
return (
<Provider value={{ current, setCurrent }}>
{props.children}
</Provider>
)
}
const count = 5
export default () => (
<Provider>
<Sections count={count} />
<Indicate count={count} />
</Provider>
)
Custom Hooks는 이전 샘플과 거의 다르지 않습니다. 화면내 판정 로직이 다소 달라, 이번은 화면 상부보다 위에 section 상변이 위치하는 경우 「화면내」라고 판정하고 있습니다.
sections/section/useStickyWrapper.ts
const useStickyWrapper = (props: Props) => {
const [state, setState] = useState<State>(...)
const options = useMemo(...)
useEffect(...) // 画面スクロール時処理
useEffect(...) // 画面内判定処理
}
이번에는 wrapper 컴포넌트와 Custom Hooks를 분리하고 있습니다.
components/sections/section/stickyWrapper.tsx
export default (props: Props) => {
const ref = useRef({} as HTMLDivElement)
useStickyWrapper({
ref,
onEnter: props.onEnter,
onLeave: props.onLeave,
throttleInterval: props.throttleInterval
})
return (
<div
className={props.className}
id={props.id}
ref={ref}
>
{props.children}
</div>
)
}
Context 상태 변경 Section
지금까지 준비한 StickyWrapper Component 를 이용해, Section 를 조립합니다. 화면 내외 판정시의 callback props 는, 부모로부터 주입되는 핸들러를 바인드 합니다.
components/sections/section/index.tsxconst View = (props: Props) => (
<StickyWrapper
id={`section${props.index}`}
className={props.className}
onEnter={props.onEnter}
onLeave={props.onLeave}
>
...
</StickyWrapper>
)
다음은 부모 Container입니다. onEnter, onLeave에서 Context current를 업데이트하고 있음을 알 수 있습니다. 동시에, 자신이 화면내에 들어가 있는지 어떤지의 플래그를 useState 로 확보해, 아이 컴퍼넌트에 주입합니다.
components/sections/section/index.tsxexport default (props: ContainerProps) => {
const [isEnter, updateState] = useState(false)
const { setCurrent } = useContext(CTX)
const onEnter = useCallback(() => {
updateState(true)
setCurrent(props.index)
}, [])
const onLeave = useCallback(() => {
updateState(false)
}, [])
return useMemo(
() => (
<StyledView
index={props.index}
title={props.title}
onEnter={onEnter}
onLeave={onLeave}
isEnter={isEnter}
isLast={props.isLast}
isFirst={props.isFirst}
/>
),
[isEnter]
)
}
Indicate
화면 오른쪽에 표시되는 현재 표시입니다. Context 상태를 참조합니다.

components/indicate/item.tsxexport default (props: ContainerProps) => {
const { current } = useContext(CTX)
const isCurrent = useMemo(() => current === props.index, [
current
])
const style = useMemo(
() =>
isCurrent
? {
transform: 'scale(1.5)',
backgroundColor: styles.blue
}
: {
transform: 'scale(1)'
},
[isCurrent]
)
return useMemo(
() => (
<StyledView index={props.index} style={style} />
),
[style]
)
}
여기도 memoize를 사보하지 않고 실시합니다. 시각 효과로는 수수합니다만, 아이디어 나름으로 여러가지 기능에 응용할 수 있을 것 같습니다.
components/indicate/item.tsxconst StyledView = styled(View)`...`
components/indicate/item.tsxconst View = (props: Props) => (
<span className={props.className} style={props.style} />
)
Reference
이 문제에 관하여(Sticky Effects), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/Takepepe/items/96229b1c676160dd195c
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
const View = (props: Props) => (
<StickyWrapper
id={`section${props.index}`}
className={props.className}
onEnter={props.onEnter}
onLeave={props.onLeave}
>
...
</StickyWrapper>
)
export default (props: ContainerProps) => {
const [isEnter, updateState] = useState(false)
const { setCurrent } = useContext(CTX)
const onEnter = useCallback(() => {
updateState(true)
setCurrent(props.index)
}, [])
const onLeave = useCallback(() => {
updateState(false)
}, [])
return useMemo(
() => (
<StyledView
index={props.index}
title={props.title}
onEnter={onEnter}
onLeave={onLeave}
isEnter={isEnter}
isLast={props.isLast}
isFirst={props.isFirst}
/>
),
[isEnter]
)
}
화면 오른쪽에 표시되는 현재 표시입니다. Context 상태를 참조합니다.

components/indicate/item.tsx
export default (props: ContainerProps) => {
const { current } = useContext(CTX)
const isCurrent = useMemo(() => current === props.index, [
current
])
const style = useMemo(
() =>
isCurrent
? {
transform: 'scale(1.5)',
backgroundColor: styles.blue
}
: {
transform: 'scale(1)'
},
[isCurrent]
)
return useMemo(
() => (
<StyledView index={props.index} style={style} />
),
[style]
)
}
여기도 memoize를 사보하지 않고 실시합니다. 시각 효과로는 수수합니다만, 아이디어 나름으로 여러가지 기능에 응용할 수 있을 것 같습니다.
components/indicate/item.tsx
const StyledView = styled(View)`...`
components/indicate/item.tsx
const View = (props: Props) => (
<span className={props.className} style={props.style} />
)
Reference
이 문제에 관하여(Sticky Effects), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/Takepepe/items/96229b1c676160dd195c텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)