useEffect(..., [props.scrollToIdx])) 要如何才能每次都执行?
在子组件内有:
// 滚动
useEffect(() => {
if(props.scrollToIdx) {
const scrollToIdx = props.scrollToIdx
console.log("滚动ID:", '#item-' + scrollToIdx!.toString())
scrollTo(scrollToIdx)
}
}, [props.scrollToIdx])
const scrollTo = (scrollToIdx: number) => {
const container = document.querySelector("#container")
const div: HTMLDivElement | null = document.querySelector('#item-' + scrollToIdx!.toString())
console.log(container, div)
if(container) {
container.scrollTo({
top: div!.offsetTop,
behavior: 'smooth'
});
}
}
在父组件
点击按钮时候会滑动:
const btnClick = () => {
console.log('点击按钮')
setSelIdx(20)
}
return (
<div className="App">
<SubContainer {...props}></SubContainer>
<button onClick={btnClick}>点击</button>
</div>
);
但是比如我在点击一次setSelIdx(20)之后,再点击,执行:setSelIdx(20)
子组件就不会更新再继续执行这个代码了:
useEffect(() => {
if(props.scrollToIdx) {
const scrollToIdx = props.scrollToIdx
console.log("滚动ID:", '#item-' + scrollToIdx!.toString())
scrollTo(scrollToIdx)
}
}, [props.scrollToIdx])
也就是说:props.scrollToIdx 没有更新这里就不会执行,请问要如何保证父组件点击(btnClick ... setSelIdx(20))
子组件这里每次都执行?
回复
1个回答

test
2024-08-11
写 React 大家容易陷入一个误区:所有的功能都得通过 props 实现,props 一般用于响应式的更新。例如你这个场景,如果 scrollToIdx 变化触发 scrollTo,scrollToIdx 不变不触发,使用 props 传递参数是合适的。按照你的描述,是希望稳定触发 scrollTo,使用 props 去控制就不合适了,这个时候应该采用命令式调用,而不是响应式更新了。可以使用 ref:
export interface SubContainerRef {
scrollTo(index: number): void;
}
export const SubContainer = forwardRef<SubContainerRef, SubContainerProps>(
(props, ref) => {
const scrollTo = (scrollToIdx: number) => {
const container = document.querySelector('#container');
const div: HTMLDivElement | null = document.querySelector(
'#item-' + scrollToIdx!.toString()
);
console.log(container, div);
if (container) {
container.scrollTo({
top: div!.offsetTop,
behavior: 'smooth',
});
}
};
useImperativeHandle(
ref,
() => ({
scrollTo,
}),
[]
);
//....
}
在父组件调用:
const conRef = useRef<SubContainerRef>();
const btnClick = () => {
conRef.current?.scrollTo(20);
};
return (
<div>
<SubContainer ref={conRef} {...props} />
<button onClick={btnClick}>点击</button>
</div>
);
总结一下:响应式更新使用 props,命令式调用使用 ref。
回复

适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容