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

如何进行反冲?

太叔逸春
2023-03-14

你如何防抖React.js?

我想防抖手柄。

我试过防抖(this.handleOnChange,200),但它不起作用。

function debounce(fn, delay) {
  var timer = null;
  return function() {
    var context = this,
      args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function() {
      fn.apply(context, args);
    }, delay);
  };
}

var SearchBox = React.createClass({
  render: function() {
    return <input type="search" name="p" onChange={this.handleOnChange} />;
  },

  handleOnChange: function(event) {
    // make ajax call
  }
});

共有3个答案

傅增
2023-03-14

在尝试了许多不同的方法后,我发现使用< code>useCallback是解决在< code>onChange事件中使用< code>debounce的多次调用问题的最简单和最有效的方法。

根据Hooks API留档,

useCallback返回回调的记忆版本,该版本仅在其中一个依赖关系发生变化时才会发生变化。

将空数组作为依赖项传递可确保回调仅被调用一次。这是一个简单的实现:

import React, { useCallback } from "react";
import { debounce } from "lodash";

const handler = useCallback(debounce(someFunction, 2000), []);

const onChange = (event) => {
    // perform any event related action here

    handler();
 };

希望这有帮助!

淳于升
2023-03-14

您可以使用事件。persist()方法。

下面是一个使用下划线的_.debounce()的示例:

var SearchBox = React.createClass({

  componentWillMount: function () {
     this.delayedCallback = _.debounce(function (event) {
       // `event.target` is accessible now
     }, 1000);
  },

  onChange: function (event) {
    event.persist();
    this.delayedCallback(event);
  },

  render: function () {
    return (
      <input type="search" onChange={this.onChange} />
    );
  }

});

编辑:查看此JSFiddle

更新:上面的例子显示了一个不受控制的组件。我一直在使用受控元素,所以这里是上面的另一个例子,但是没有使用< code>event.persist()“欺骗”。

JSFiddle也可用。不带下划线的示例

var SearchBox = React.createClass({
    getInitialState: function () {
        return {
            query: this.props.query
        };
    },

    componentWillMount: function () {
       this.handleSearchDebounced = _.debounce(function () {
           this.props.handleSearch.apply(this, [this.state.query]);
       }, 500);
    },

    onChange: function (event) {
      this.setState({query: event.target.value});
      this.handleSearchDebounced();
    },

    render: function () {
      return (
        <input type="search"
               value={this.state.query}
               onChange={this.onChange} />
      );
    }
});


var Search = React.createClass({
    getInitialState: function () {
        return {
            result: this.props.query
        };
    },

    handleSearch: function (query) {
        this.setState({result: query});
    },

    render: function () {
      return (
        <div id="search">
          <SearchBox query={this.state.result}
                     handleSearch={this.handleSearch} />
          <p>You searched for: <strong>{this.state.result}</strong></p>
        </div>
      );
    }
});

React.render(<Search query="Initial query" />, document.body);

编辑:更新了React 0.12的示例和JSFiddles

编辑:更新示例以解决Sebastien Lorber提出的问题

编辑:使用不使用下划线并使用普通javascript去抖动的jsfiddle进行了更新。

张俊茂
2023-03-14

这是我如何解决这个问题的最新版本。我会使用:

  • 真棒-去抖-promise去抖动异步函数
  • 使用常量将该去抖函数存储到组件中
  • 反应异步挂钩,将结果导入我的组件

这是一些初始连接,但您是自己组成基本块的,您可以制作自己的自定义钩子,这样您只需要做一次。

// Generic reusable hook
const useDebouncedSearch = (searchFunction) => {

  // Handle the input text state
  const [inputText, setInputText] = useState('');

  // Debounce the original search async function
  const debouncedSearchFunction = useConstant(() =>
    AwesomeDebouncePromise(searchFunction, 300)
  );

  // The async callback is run each time the text changes,
  // but as the search function is debounced, it does not
  // fire a new request on each keystroke
  const searchResults = useAsync(
    async () => {
      if (inputText.length === 0) {
        return [];
      } else {
        return debouncedSearchFunction(inputText);
      }
    },
    [debouncedSearchFunction, inputText]
  );

  // Return everything needed for the hook consumer
  return {
    inputText,
    setInputText,
    searchResults,
  };
};

然后你可以使用你的钩子:

const useSearchStarwarsHero = () => useDebouncedSearch(text => searchStarwarsHeroAsync(text))

const SearchStarwarsHeroExample = () => {
  const { inputText, setInputText, searchResults } = useSearchStarwarsHero();
  return (
    <div>
      <input value={inputText} onChange={e => setInputText(e.target.value)} />
      <div>
        {searchResults.loading && <div>...</div>}
        {searchResults.error && <div>Error: {search.error.message}</div>}
        {searchResults.result && (
          <div>
            <div>Results: {search.result.length}</div>
            <ul>
              {searchResults.result.map(hero => (
                <li key={hero.name}>{hero.name}</li>
              ))}
            </ul>
          </div>
        )}
      </div>
    </div>
  );
};

你会发现这个例子在这里运行,你应该阅读 react 异步钩子文档,了解更多细节。

我们通常希望消除API调用的干扰,以避免后端充斥无用的请求。

2018年,使用回调(Lodash/下划线)对我来说感觉很糟糕,而且容易出错。由于API调用以任意顺序解析,很容易遇到样板文件和并发问题。

我已经创建了一个小库,用React来解决你的痛苦:令人敬畏的防抖promise。

这不应该比这更复杂:

const searchAPI = text => fetch('/search?text=' + encodeURIComponent(text));

const searchAPIDebounced = AwesomeDebouncePromise(searchAPI, 500);

class SearchInputAndResults extends React.Component {
  state = {
    text: '',
    results: null,
  };

  handleTextChange = async text => {
    this.setState({ text, results: null });
    const result = await searchAPIDebounced(text);
    this.setState({ result });
  };
}

脱粘功能确保:

  • API 调用将被去抖
  • 去抖动函数始终返回promise
  • 只有最后一个电话的返回promise才会解决
  • 单个此设置状态({ 结果 }); 将在每个 API 调用中发生

最后,如果您的组件被卸载,您可以添加另一个技巧:

componentWillUnmount() {
  this.setState = () => {};
}

请注意,可观察对象(RxJS)也非常适合分解输入,但它是一种更强大的抽象,可能更难正确学习/使用。

这里的重要部分是为每个组件实例创建一个解除阻塞(或节流)的函数。您不希望每次都重新创建解抖(或油门)函数,也不希望多个实例共享同一个解抖函数。

我并没有在这个答案中定义去抖动函数,因为它并不真正相关,但这个答案将与_完美结合。去抖下划线或lodash的,以及任何用户提供的去抖功能。

由于去抖函数是有状态的,我们必须为每个组件实例创建一个去抖函数。

ES6(类属性):推荐

class SearchBox extends React.Component {
    method = debounce(() => { 
      ...
    });
}

ES6(类构造函数)

class SearchBox extends React.Component {
    constructor(props) {
        super(props);
        this.method = debounce(this.method.bind(this),1000);
    }
    method() { ... }
}

ES5系统

var SearchBox = React.createClass({
    method: function() {...},
    componentWillMount: function() {
       this.method = debounce(this.method.bind(this),100);
    },
});

请参阅JsFiddle:3个实例为每个实例生成1个日志条目(即全球生成3个日志条目)。

var SearchBox = React.createClass({
  method: function() {...},
  debouncedMethod: debounce(this.method, 100);
});

它不会工作,因为在类描述对象创建过程中,这个不是自己创建的对象<代码>此。方法没有返回您所期望的结果,因为这个context不是对象本身(BTW实际上还不存在,因为它刚刚创建)。

var SearchBox = React.createClass({
  method: function() {...},
  debouncedMethod: function() {
      var debounced = debounce(this.method,100);
      debounced();
  },
});

这一次,您实际上是在创建一个调用 this.method 的反冲函数。问题是,您正在每个去抖的Method调用上重新创建它,因此新创建的去抖函数对以前的调用一无所知!随着时间的推移,您必须重用相同的去抖动函数,否则不会发生去抖动。

var SearchBox = React.createClass({
  debouncedMethod: debounce(function () {...},100),
});

这有点棘手。

该类的所有挂载实例将共享相同的去抖函数,大多数情况下这不是您想要的!请参见 JsFiddle:3 个实例在全球范围内仅生产 1 个日志条目。

您必须为每个组件实例创建一个去噪函数,而不是在类级别创建一个由每个组件实例共享的去噪函数。

这是相关的,因为我们经常想要防抖或限制DOM事件。

在React中,您在回调中收到的事件对象(即SyntheticEvent)被池化(现在有文档记录)。这意味着在调用事件回调后,您收到的SyntheticEvent将被放回具有空属性的池中,以减少GC压力。

因此,如果您将SyntheticEvent属性异步访问原始回调(如果您限制/防抖可能会出现这种情况),您访问的属性可能会被擦除。如果您希望事件永远不会放回池中,您可以使用持久()方法。

onClick = e => {
  alert(`sync -> hasNativeEvent=${!!e.nativeEvent}`);
  setTimeout(() => {
    alert(`async -> hasNativeEvent=${!!e.nativeEvent}`);
  }, 0);
};

第二个(异步)将打印< code > hasNativeEvent = false ,因为事件属性已被清除。

onClick = e => {
  e.persist();
  alert(`sync -> hasNativeEvent=${!!e.nativeEvent}`);
  setTimeout(() => {
    alert(`async -> hasNativeEvent=${!!e.nativeEvent}`);
  }, 0);
};

第二个(异步)将打印hasNativeEvent=true,因为持久化允许您避免将事件放回池中。

你可以在这里测试这两个行为

阅读Julen的答案,了解使用persist()和节流/去抖功能的示例。

 类似资料:
  • 问题内容: 如何在Go中反转任意切片()?我宁愿不必编写和使用。有没有简单的内置方法来做到这一点? 问题答案: 没有一个简单的,内置的用于反转接口{}的部分。您可以编写一个for循环来做到这一点: Go 1.8中引入的reflect.Swapper函数可用于编写通用的反转函数: 游乐场的例子

  • 问题内容: 我很确定它具有内置功能,但是在搜索或在文档中找不到任何内容。是否启用了启用multidex的标记? 另一个要注意的是:有什么方法可以查看哪些库弄乱了您的方法数量?达到64k的限制令人惊讶。 问题答案: 在其他地方找到答案。与为任何常规Android项目启用它没什么不同。 至于方法计数,此站点可以解决问题:http : //inloop.github.io/apk-method-coun

  • 我不熟悉反应式编程。为了得到我的手,我试图建立一个简单的RESTAPI,但与请求验证和数据库操作。 以下是我想做的步骤。 验证传入请求参数 验证后保持继续链并从数据库获取 如果用户不存在于db返回一些错误响应 如果用户存在,返回带有用户名的成功响应 注意:请求和响应由类(UserRequest和UserResponse)表示。DB=使用无功驱动程序的Mongo。 我已经完成了验证工作,但现在我不知

  • 来自REST服务的json对象 使用JacksonInFiveMinutes中的代码 ObjectMapper mapper=new ObjectMapper(); Map userData=mapper.read值(webResource.queryParams(queryParams). get(String.class);, Map.class); 在哪里: 从REST服务返回json 从J

  • 问题内容: 我使用以下行以相反的顺序对浮点数组进行排序,但出现错误消息,这是什么问题? 错误:找不到符号 符号:方法sort(float [],java.util.Comparator)位置:类java.util.Arrays Arrays.sort(sortedData,Collections.reverseOrder()); ==================================

  • 我正在使用java lambda对列表进行排序。 我怎样才能反向排序呢?