Photo Carousel

13383 단어 React후크
별칭 Hero Images라고 합니다. 랜딩 페이지 등에서 한 번은 사용한 적이 있다고 생각합니다. 시간차로 자동 슬라이드하는 가장 간단한 것을 소개합니다.
code: github/$ yarn 1205






Component의 사용감은 다음과 같습니다. 이미지는 background-size: cover 로 지정되어 표시 영역 중앙 가득 표시됩니다. 이미지 비율이 흩어져 있어도, 가로폭에 대한 높이 비율( imageRatio )로 통일 조정 가능하게 되어 있습니다.

components/hero.tsx
<PhotoCarousel
  images={Images} // string[]
  imageRatio={0.66}
  transitionInterval={4000}
  transitionDuration={400}
  onChangeCurrent={setCurrent}
/>

Component 개요도



이미지는 몇 장 고정을 상정하고 있으므로, 이번은 갑자기 모두 마운트합니다. 화상 Component 를 설치하는 Container 폭은 「화상수 * 화면폭」을 지정. 각 이미지 Component 좌표는 index 나누어 설치. 현재를 전환하여 Container 좌표를 이동합니다. animation 동력은 CSS animation입니다.



State Bubbling



PhotoCarousel 에 보관 유지하고 있는 current 는, Indicate Component 의 관심마다이기도 합니다. (↓)



current 의 변경을 외부에 전파하는 수단으로서, 변경에 응해 callback 함수를 트리거하는 effect 를 추가합니다. PhotoCarousel Component 의 부모 Component 는, 별도 current 를 보관 유지해, 자신의 setCurrent 함수를 callback props 에 바인드 합니다. 이렇게 하면, 자식 Component 의 State 를 빨아 올릴 수가 있습니다.

components/hero.tsx
const View = (props: Props) => {
  const [current, setCurrent] = useState(0) // here
  return (
    <div className={props.className}>
      <PhotoCarousel
        images={Images}
        imageRatio={0.66}
        transitionInterval={4000}
        transitionDuration={400}
        onChangeCurrent={setCurrent} // here
      />
      <div className="indicate">
        <Indicate
          current={current} // here
          color="light"
          count={Images.length}
        />
      </div>
    </div>
  )
}

State Bubbling 은 간편하게 이용할 수 있는 반면, 많은 Component 의 관심 마다 고 계층에 전파하는 것은 적합하지 않습니다.
  • 같은 값을 표현하고 싶은 것이 중복되어 있는 것
  • 각 계층에 대해 Hooks API와 callback 함수가 필요합니다
  • 단방향 데이터 흐름의 역행으로도 포착됩니다

  • 이 정도의 문맥에 닫기에는 하나의 수단으로서 사용할 수 있습니다만, 조기에 ContextAPI 혹은 reducer 에 태우는 것이 적절하겠지요.

    usePhotoCarousel



    이번에 정의한 Custom Hooks 개요입니다.

    components/photoCarousel/usePhotoCarousel.tsx
    const usePhotoCarousel = (props: Props) => {
      const [state, update] = useState<State>(...)
      const options = useMemo(...)
      const nodeStyle = useMemo(...)
      const containerStyle = useMemo(...)
      useEffect(...) // 画面リサイズに対応する effect
      useEffect(...) // 所定時間で切り替える effect
      useEffect(...) // current 変更の callback を叩く effect
      return {
        current: state.current,
        renderItems,
        nodeStyle,
        containerStyle
      }
    }
    

    화면 리사이즈에 대응하는 effect



    State 에 표시 영역 비율의 근원이 되는, 종횡을 보관 유지합니다.

    components/photoCarousel/usePhotoCarousel.tsx
    useEffect(() => {
      const handleResize = () => {
        if (props.ref.current === null) return
        const {
          width,
          height
        } = props.ref.current.getBoundingClientRect()
        update(_state => ({ ..._state, width, height }))
      }
      handleResize()
      window.addEventListener('resize', handleResize)
      return () =>
        window.removeEventListener('resize', handleResize)
    }, [])
    

    소정 시간에 전환 effect



    도중에 인터벌이 변경하는 일도 별로 없지만, memoize 대상으로 하고 있습니다.

    components/photoCarousel/usePhotoCarousel.tsx
    useEffect(
      () => {
        const id = setInterval(() => {
          update(_state => {
            const current =
              _state.current === options.imagesCount - 1
                ? 0
                : _state.current + 1
            return { ..._state, current }
          })
        }, options.transitionInterval)
        return () => clearInterval(id)
      },
      [options.transitionInterval]
    )
    

    current 변경 callback 을 두드리는 effect



    Optional Injection이 있으면 바인딩된 함수를 두드립니다.

    components/photoCarousel/usePhotoCarousel.tsx
    useEffect(
      () => {
        if (options.onChangeCurrent === null) return
        options.onChangeCurrent(state.current)
      },
      [state.current]
    )
    

    좋은 웹페이지 즐겨찾기