当前位置: 首页 > 知识库问答 >
问题:

javascript - useEffect(..., [props.scrollToIdx])) 要如何才能每次都执行?

袁何平
2024-08-04

在子组件内有:


    // 滚动
    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个答案

舒枫涟
2024-08-04

为了确保 useEffect 钩子在 props.scrollToIdx 更改时总是执行,你需要确保 props.scrollToIdx 的值在每次点击时确实发生了变化。从你的描述来看,问题可能出在 props.scrollToIdx 的值在第二次点击时并没有真正改变(即它仍然是 20),因此 React 认为依赖项没有变化,因此不会重新运行 useEffect

要解决这个问题,你可以考虑以下几种方法:

  1. 确保 props.scrollToIdx 的值在每次点击时都不同
    如果 scrollToIdx 总是指向同一个值(如 20),则 useEffect 不会重新运行。你可以通过添加一个时间戳或递增的计数器来确保每次 scrollToIdx 都不同。
  2. 使用 useStateuseEffect 在子组件中控制滚动
    如果父组件仅仅是为了触发滚动,你可以考虑在子组件内部使用 useState 来控制滚动,而不是直接从 props 中获取。

方法 1: 更改 props.scrollToIdx 的值

在父组件中,你可以添加一个额外的状态来确保 scrollToIdx 每次都不同:

const [scrollCounter, setScrollCounter] = useState(0);

const btnClick = () => {
  console.log('点击按钮');
  setSelIdx(20);
  setScrollCounter(prev => prev + 1); // 更新计数器
}

// 传递 scrollCounter 或结合 selIdx 和 scrollCounter 作为新的 prop
return (
  <div className="App">
    <SubContainer scrollToIdx={[selIdx, scrollCounter]}></SubContainer>
    <button onClick={btnClick}>点击</button>
  </div>
);

然后在子组件中,你需要相应地调整 useEffect 依赖项和滚动逻辑。

方法 2: 在子组件中使用 useState

在子组件中,你可以使用 useState 来存储 scrollToIdx 的值,并在父组件触发时更新它:

// 子组件
const [localScrollToIdx, setLocalScrollToIdx] = useState(props.initialScrollToIdx || null);

useEffect(() => {
  if (props.scrollToIdx !== undefined) {
    setLocalScrollToIdx(props.scrollToIdx);
  }
}, [props.scrollToIdx]);

useEffect(() => {
  if (localScrollToIdx) {
    console.log("滚动ID:", '#item-' + localScrollToIdx.toString());
    scrollTo(localScrollToIdx);
  }
}, [localScrollToIdx]);

// ... 其余代码 ...

在父组件中,你只需传递初始的 scrollToIdx(如果需要的话),并在需要时更新它:

const [selIdx, setSelIdx] = useState(null);

const btnClick = () => {
  console.log('点击按钮');
  setSelIdx(20);
}

return (
  <div className="App">
    <SubContainer initialScrollToIdx={selIdx}></SubContainer>
    <button onClick={btnClick}>点击</button>
  </div>
);

这样,每次 selIdx 更新时,都会通过 props 传递给子组件,子组件的 useEffect 钩子将检测到 props.initialScrollToIdx 的变化(如果作为依赖项),但更推荐的做法是使用内部状态 localScrollToIdx 来控制滚动行为。

 类似资料:
  • 在进行单元测试时,执行一个测试类就要启动springboot项目,加载上下文数据,每次执行一次测试都要再重新加载上下文环境.这样导致每一次单元测试时都会花3-5分钟时间。如何解决这个问题? 网上找不到什么简单的可行方案

  • vue2开发 需求是没间隔多上时间请获取一次token、token是10分钟有效、我需要在7分钟的时候刷新一次token、然后我使用的是setInterval()方法 没7分钟请求一次, 但是出现的问题是、页面刷线以后setInterval()方法又重新执行了一次、导致没有正常刷新token 如何解决setInterval页面刷新以后不再重新执行 或者利用其他方法

  • uniapp 为什么每次进来都会执行onLoad钩子? 症状:不管是第一次还是第N次进去都会执行onload,印象中应该只有第一次进来才会执行一次吧,有谁遇到过吗,难道是用redirectTo跳转才会这样吗

  • 用的是vue-element-admin架子. 点击一个菜单连接后打开一个列表(A.create), 点击列表中的一个项(B.create)打开B页面. 再关闭B页面, 此时再回到A, 此时又执行了A页面的create方法 开发时以上操作不会触发A页面的create, 现在莫名的都create了

  • 我正在运行带有 WSL2 的视窗 10。我正在使用带有远程 - WSL扩展名的VSCode从我的wsl文件系统中打开文件。 当我启动我的Windows笔记本电脑并打开VSCode时,我收到以下错误: 当我执行<code>wsl时。exe——关闭PowerShell中的</code>,然后重新启动Docker Desktop,一切正常。但每次笔记本电脑重启后,我都必须这样做。 远程WSL扩展版本:v

  • 问题内容: 我有一个javascript函数,我希望在JSF 2中进行每次异步回发后执行。 我已执行以下操作以确保执行此每整页回发: 我需要执行此操作的原因是为了解决第三方JSF组件库中的故障,因此我无法在服务器呈现阶段中进行任何修改来对此组件执行此操作。 我可能找不到有关此问题的信息,可能是因为我使用了不正确的术语。我曾经是ASP.NET开发人员,我将这些术语称为“整页回发”和“部分回发”,而其

  • 我想每10秒执行一段代码。我在这个论坛上找到了一个例子,但我的实现有一些问题。 我得到这个错误,指向:

  • 这是我使用的代码 我不明白为什么当我使用类名“yt-simple-endpoint inline-block style-scope YTD-thumbnail”时,我什么也没得到,但相同的代码却在处理“style-scope YTD-grid-video-renderer” 你能帮我吗?