无效的挂钩调用.钩子只能在轮播组件中的函数组件主体内部调用



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

//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>
)
}

resizeWindow 是一个自定义钩子,你不应该在 useEffect 钩子中使用它。这种用法会给你一个错误。

此外,您必须通过在自定义钩子的名称前面加上use来命名您的自定义钩子

此外,您必须在 resizeWindow hook 中的 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>
)
}

最新更新