无效的挂钩调用。在Carousel组件中,只能在函数组件的主体内部调用钩子

问题描述 投票:0回答:1

我正在使用useLayoutEffect构建Carousel组件。此useLayoutEffect挂钩已在resizeWindow.ts中单独设置。在名为carousel的功能组件中调用resizeWindow函数。我找不到违反规则的地方。

//resizeWindow.ts 

  import { useLayoutEffect, useState, RefObject } from 'react'

/***
 * @function resizeWindow
 * this function is custom hook for grab resizing innerWidth of element.
 * 
 * 
 */
export const resizeWindow: (ref: RefObject<HTMLElement>) => number[]  = (ref) => {
  const [ elementWidth, elementHeight ] = ref.current ?  
    [ref.current.offsetWidth, ref.current.offsetHeight ] :
    [0,0];
  const [size, setSize] = useState([elementWidth, elementHeight]);
  useLayoutEffect(() => {
    const updateSize = () => {
      setSize([elementWidth, elementHeight]);
      console.log(`elementWidth: ${elementWidth}px`);
    };
    updateSize(); 
    window.addEventListener('resize', updateSize);

    return () => window.removeEventListener('resize', updateSize);
  },[]);
  return size;    
};

//carousel.ts
//

import { resizeWindow } from './resizeWindow.ts'; 

export const Carousel: FC = ({
  children
}) => {
  const parentRef = useRef<HTMLDivElement>(null); 
  const slideRef = createRef<HTMLDivElement>(); 

  const [count, setCount ] = useState<number>(0); 
  const [parentWidth, setParentWidth] = resizeWindow(parentRef); 

  const total = React.Children.count(children); 
  const nextSlide = () => {
    if( count < total -1 ){
      setCount( count + 1 );
    } else if( count === total-1 ){
      setCount(1); 
    }
  }
  const prevSlide = () => {
    if( count > 0 ){
      setCount( count -1 );
    } else if( count === 0 ){
      setCount(total -1 );
    }
  }
  useEffect(()=> {
    console.log('parentRef: ', parentRef); 
    if(slideRef.current){
      slideRef.current.style.transition = "all 0.5s ease-in-out";
      slideRef.current.style.transform = `translateX(-${count}00%)`;
    }
    if(parentRef.current){
      resizeWindow(parentRef);
    }
  },[count || parentWidth])
  return(
    <SliderContainer ref={parentRef}>
      <Slider ref={slideRef} width={parentWidth * total}>
        {children}        
      </Slider>   
      <Indicator now={1} total={total}/>
      <Button onClick={prevSlide}>left</Button>
      <Button onClick={nextSlide}>right</Button>
    </SliderContainer>
  )
}

reactjs typescript
1个回答
0
投票

resizeWindow是一个自定义钩子,不应在useEffect钩子中使用它。这种用法使您出错。

此外,您还必须在自定义钩子的前面加上use作为其名称来命名>

此外,您还必须在resizeWindow挂钩中的updateSize函数中解构ref属性,以便您不会在updateSize函数中遇到关闭问题

更新的解决方案将看起来像

export const useResizeWindow: (ref: RefObject<HTMLElement>) => number[]  = (ref) => {
  const [size, setSize] = useState([elementWidth, elementHeight]);
  useLayoutEffect(() => {
    const updateSize = () => {
      const [ elementWidth, elementHeight ] = ref.current ?  
       [ref.current.offsetWidth, ref.current.offsetHeight ] :
       [0,0];
      setSize([elementWidth, elementHeight]);
      console.log(`elementWidth: ${elementWidth}px`);
    };
    updateSize(); 
    window.addEventListener('resize', updateSize);

    return () => window.removeEventListener('resize', updateSize);
  },[]);
  return size;    
};

及其用法如下

//carousel.ts
//

import { useResizeWindow } from './resizeWindow.ts'; 

export const Carousel: FC = ({
  children
}) => {
  const parentRef = useRef<HTMLDivElement>(null); 
  const slideRef = createRef<HTMLDivElement>(); 

  const [count, setCount ] = useState<number>(0); 
  const [parentWidth, setParentWidth] = useResizeWindow(parentRef); 

  const total = React.Children.count(children); 
  const nextSlide = () => {
    if( count < total -1 ){
      setCount( count + 1 );
    } else if( count === total-1 ){
      setCount(1); 
    }
  }
  const prevSlide = () => {
    if( count > 0 ){
      setCount( count -1 );
    } else if( count === 0 ){
      setCount(total -1 );
    }
  }
  useEffect(()=> {
    console.log('parentRef: ', parentRef); 
    if(slideRef.current){
      slideRef.current.style.transition = "all 0.5s ease-in-out";
      slideRef.current.style.transform = `translateX(-${count}00%)`;
    }
  },[count || parentWidth])
  return(
    <SliderContainer ref={parentRef}>
      <Slider ref={slideRef} width={parentWidth * total}>
        {children}        
      </Slider>   
      <Indicator now={1} total={total}/>
      <Button onClick={prevSlide}>left</Button>
      <Button onClick={nextSlide}>right</Button>
    </SliderContainer>
  )
}
    
© www.soinside.com 2019 - 2024. All rights reserved.