如何正确等待状态更新/渲染,而不使用延迟/超时功能?

时间:2019-03-20 21:01:22

标签: javascript reactjs lodash react-hooks

我将尽量保持简短,但是我不确定100%正确的方法来实现我的目标。我在没有太多培训的情况下就陷入了React的深渊,所以我很可能会错误地处理大部分此组件,正确方向的观点肯定会有所帮助,我真的不希望有人完全重做对我来说是我的组成部分,因为它很长。

我有一个导航栏SubNav,该导航栏基于url / path查找当前处于活动状态的项目,然后将移动下划线元素,该元素继承了活动元素的宽度。为此,我找到了活动项目的位置以及相应的位置。当用户将鼠标悬停在另一个导航项上或调整窗口大小时,也会相应地调整位置。

在较低分辨率下,当导航被切断以使箭头在导航上向左/向右滚动以查看所有导航项目时,我也有它。

此外,如果分辨率较低且当前处于活动状态的导航项目不在屏幕上,则导航将滚动到该项目,然后正确定位下划线。

目前,此功能与组件中的功能相同,但问题是,我不正确地执行此操作,我正在使用lodash函数delay来延迟某些时间(我想得到某些导航项的正确位置,因为在函数调用时这是不正确的),我觉得这不是走的路。这完全取决于页面加载的速度等,并且每个用户的浏览速度都不一样。

_.delay(
        () => {
          setSizes(getSizes()),
            updateRightArrow(findItemInView(elsRef.length - 1)),
            updateLeftArrow(findItemInView(0));
        },
        400,
        setArrowStyle(styling)
      );

不使用延迟,从我的状态返回的值是错误的,因为尚未设置。

我的问题是,我该如何正确处理?我知道我的以下代码有些可读性,但是我提供了一个CODESANBOX来玩。

我有3个主要功能,它们相互依赖:

  1. getPostion()
    • 此函数查找活动的导航项,检查它是否在视口内,如果不在视口内,则它将更改导航的left位置,使其成为屏幕上最左侧的导航项,并通过{{ 1}}将下划线直接移到下面。
  2. setSizes(getSizes())
    • 这被称为getSizes()中的参数以更新setSizes状态,该状态将返回所有导航项的左右边界
  3. sizes
    • 这被称为getUnderlineStyle()函数中setUnderLineStyle中的一个参数,用于相对于从getSizes()状态抓取的活动导航项的位置来更新下划线对象的位置,但由于状态尚未设置,因此我必须在sizes中将sizesObj作为参数传递。我认为这是我开始困惑的地方,我想给人的印象是,当我设置状态时,便可以访问它。因此,我开始使用setSizes进行战斗。

下面是我的整个组件,但可以在CODESANBOX中看到它

delay

3 个答案:

答案 0 :(得分:2)

您可以使用useLayoutEffect挂钩来确定值是否已更新并采取措施。由于要确定是否所有值都已更新,因此需要在useEffect中比较新旧值。您可以参考以下文章,了解如何编写usePrevious自定义钩子

How to compare oldValues and newValues on React Hooks useEffect?

const oldData = usePrevious({ rightArrow, leftArrow, sizes});
useLayoutEffect(() => {
   const {rightArrow: oldRightArrow, leftArrow: oldLeftArrow, sizes: oldSizes } = oldData;
  if(oldRightArrow !== rightArrow && oldLeftArrow !== leftArrow and oldSizes !== sizes) {
      setArrowStyle(styling)
  }
}, [rightArrow, leftArrow, sizes])

答案 1 :(得分:0)

setState带有可选的second argument,这是在状态更新和组件重新呈现后执行的回调。

另一种选择是componentDidUpdate生命周期方法。

答案 2 :(得分:0)

我认为您需要延迟的原因在这里,因为您是根据第一个和最后一个元素的矩形进行计算的,这些矩形在单击按钮并进行500ms滚动动画时会受到影响。因此,您的计算需要等待动画完成。更改动画的数量并延迟您将看到的关系。

我的意思。

@include transition(all 500ms ease);

简而言之,只要您有与计算相关的动画,我认为您使用的是正确的方法。