阅读 845

React 函数式组件中使用防抖节流不生效?

在 class 组件中使用防抖/节流,通常使用 debounce/ throttle 包裹需要防抖/节流的函数,即可创建一个防抖或节流的函数:

import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Input } from 'antd';
import throttle from 'lodash/debounce';

class Search extends React.Component {
    constructor(props) {
      super(props)
      this.handleSearch = throttle(this.handleOnChange, 200);
    }
 
    handleOnChange = (e) => {
      console.log(e.target.value)
    }
    render() {
        return (
            <Input onChange={this.handleSearch} />
        )
    }
}

ReactDOM.render(
  <Search />,
  document.getElementById('container'),
);
复制代码

当我们在函数式组件中使用防抖/节流函数时,也会自然而然地使用 debounce/ throttle 包裹需要防抖/节流的函数:

import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Input } from 'antd';
// import debounce from 'lodash/debounce';
import throttle from 'lodash/throttle';

const Search = () => {

  const handleOnChange = (e) => {
    console.log(e.target.value)
  }
  const handleSearch = throttle((e) => handleOnChange(e), 500)



  return (<Input onChange={handleSearch}  placeholder="Basic usage" />)
}

ReactDOM.render(<Search />, document.getElementById('container'));
复制代码

却发现做了防抖节流的函数并没有发挥作用,而是仅仅把时间延后了500毫秒而已。这是因为函数式组件每次渲染结束后,内部的变量都会被释放,重新渲染时所有的变量都会被重新初始化,产生的结果就是每一次都注册和执行了 setTimeout 函数。想要得到正确的运行结果,必须以某种方式存储那些会被删除的变量和方法的引用,遗憾的是没办法直接使用 useState 这个 hook 去存储。那么我们通过什么方式存储呢?欣慰的是,useCallback 和 useRef 这两个 hook 可以解决我们的问题。

useCallback

当把一个回调函数以依赖项数组作为参数传入 useCallback,它将返回一个缓存后的函数。

import React, { useCallback } from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Input } from 'antd';
import debounce from 'lodash/debounce';
import throttle from 'lodash/throttle';

const Search = () => {

  const handleOnChange = (e) => {
    console.log(e.target.value)
  }
  const handleSearch = useCallback(throttle((e) => handleOnChange(e), 500), [])

  return (<Input onChange={handleSearch}  placeholder="Basic usage" />)
}

ReactDOM.render(<Search />, document.getElementById('container'));
复制代码

useRef

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象梓组件的整个生命周期内保持不变。

import React, { useRef } from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Input } from 'antd';
import debounce from 'lodash/debounce';
import throttle from 'lodash/throttle';

const Search = () => {

  const handleOnChange = (e) => {
    console.log(e.target.value)
  }
  const handleSearch = useRef(throttle((e) => handleOnChange(e), 500)).current

  return (<Input onChange={handleSearch}  placeholder="Basic usage" />)
}

ReactDOM.render(<Search />, document.getElementById('container'));
复制代码


文章分类
前端
文章标签