使用 lodash debounce 时 React 挂钩状态出现问题

Issue with React hook state while working with lodash debounce

我不太确定到底是什么导致了这个问题。所以我有一个组件可以根据某些动作显示图片的数量。我有一个滑块和一个下拉组件来模拟操作。

我在滑块上使用 lodash 去抖动。所以确切的问题是我有一个状态来跟踪过滤器的初始值,比如带有 dog

的类别
const initialValue = {
  filters: [
    {
      field: "category",
      values: ["dog"]
    }
  ]
}
const [myFilter, setMyFilter] = useState(initialValue)

有了上面的初始值,组件会抓取所有类别为狗的图片并显示在页面上。然后我可以添加一个下拉值来过滤掉图像大小,所以我的状态输出如下:

 myFilter = {
   filters: [
     {
       field: "category",
       values: ["dog"]
     },
     {
       field: "size",
       values: ["500x500"]
     }
   ]
 }

此时我的最新状态应该如上。我为时间范围添加了一个 debounce 以便函数如下所示

onTimeRangeChange = (value) => {
  // update range state
  setRange(value);
}

const handleSetTimeRange = (value: number[]) => {
    const merge = {
      time_range: {
        start_time: moment(startTime + value[0] * 1000).toISOString(),
        end_time: moment(startTime + value[1] * 1000).toISOString(),
      },
    };

    console.log("myFilter: ", myFilter);
    setMyFilter({ ...myFilter, time_range: merge });
  };

const handleDebounce = useCallback(debounce(handleSetTimeRange, 500), [])

useEffect(() => {
  if(prevRange && oneRange !== prevRange)
  {
     handleDebounce(range)
  }
}, [range])

所以myFilter毕竟预计是

  myFilter = {
    filters: [
     {
       field: "category",
       values: ["dog"]
     },
     {
       field: "size",
       values: ["500x500"]
     }
   ],
   time_range: {
        start_time: moment(startTime + value[0] * 1000).toISOString(),
        end_time: moment(startTime + value[1] * 1000).toISOString(),
   }
 }

但实际值如下所示:

myFilter = {
    filters: [
     {
       field: "category",
       values: ["dog"]
     }
   ],
   time_range: {
        start_time: moment(startTime + value[0] * 1000).toISOString(),
        end_time: moment(startTime + value[1] * 1000).toISOString(),
   }
 }

它以某种方式删除了过滤器下的尺寸对象。我不确定实际发生了什么,我对 debounce 和 useCallback 不是很熟悉。他们会重置状态吗?

看起来 useCallback 挂钩有一个空的依赖数组,

const handleDebounce = useCallback(debounce(handleSetTimeRange, 500), []);

因此初始 myFilter 状态值在回调范围内关闭并且从未更新。

const handleSetTimeRange = (value: number[]) => {
  const merge = {
    time_range: {
      start_time: moment(startTime + value[0] * 1000).toISOString(),
      end_time: moment(startTime + value[1] * 1000).toISOString(),
    },
  };

  console.log("myFilter: ", myFilter);
  setMyFilter({ ...myFilter, time_range: merge });
};

您可能可以将 myFilter 添加到 useCallback 挂钩的依赖项数组以将更新后的 myFilter 状态值重新包含在回调范围中:

const handleDebounce = useCallback(
  debounce(handleSetTimeRange, 500),
  [myFilter],
);

或使用功能状态更新从任何先前状态正确更新:

const handleSetTimeRange = (value: number[]) => {
  const merge = {
    time_range: {
      start_time: moment(startTime + value[0] * 1000).toISOString(),
      end_time: moment(startTime + value[1] * 1000).toISOString(),
    },
  };

  setMyFilter(myFilter => {
    return {
      ...myFilter,
      time_range: merge
    }
  });
};