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

在React.js中执行去盎司

郁承运
2023-03-14

如何在React.js中执行去盎司?

我想把零钱去掉。

我试过使用debounce(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

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

根据钩子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

可以使用event.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} />
    );
  }

});

编辑:查看此JSFIDLE

更新:上述示例显示了一个非受控组件。我一直在使用受控元素,所以这里是上面的另一个示例,但没有使用event.persist()“trickery”。

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

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);

编辑:更新了示例和JSFiddles以响应0.12

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

编辑:使用JSFIDLE进行更新,JSFIDLE不使用下划线,并使用纯javascript解块。

华季同
2023-03-14

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

  • awesome-防抖-promise防抖异步功能
  • use常量将该反跳函数存储到组件中
  • react-async钩子将结果输入到我的组件中

这是一些初始布线,但是您正在自己组成原始块,您可以制作自己的自定义钩子,这样您只需要做一次。

// 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-async-ook留档了解更多详细信息。

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

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

我创建了一个小图书馆,里面有React来解决你的痛苦:很棒的debounce 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才能解决问题
  • 单个this.setState({result}) 将在每个API调用中发生

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

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

请注意,可观测数据(RxJS)也非常适合反跳输入,但它是一个更强大的抽象,可能更难正确学习/使用。

这里最重要的部分是为每个组件实例创建一个单独的取消(或限制)函数。您不希望每次都重新创建防抖(或油门)函数,也不希望多个实例共享相同的去抖函数。

我没有在这个答案中定义去平衡函数,因为它并不真正相关,但是这个答案在_中非常好。防抖的下划线或倒装,以及任何用户提供的去倒装功能。

因为去噪函数是有状态的,所以我们必须为每个组件实例创建一个去噪函数。

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);
});

它不起作用,因为在类描述对象创建过程中,这个不是自己创建的对象this.method不会返回您期望的结果,因为this上下文不是对象本身(实际上还不存在,因为它刚刚被创建)。

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

这一次,您正在有效地创建一个取消公告的函数,该函数调用您的This.method。问题是每次调用debouncedMethod时都要重新创建它,因此新创建的debounce函数对以前的调用一无所知!随着时间的推移,必须重复使用相同的去抖动功能,否则将不会发生去抖动。

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

这有点棘手。

该类的所有已装入实例将共享同一个取消公告的函数,通常这不是您想要的!。请参阅JSFIDLE:3个实例全局只生成1个日志条目。

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

这是相关的,因为我们经常希望消除或限制DOM事件。

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

因此,如果您异步访问原始回调的SyntheticEvent属性(如节流/去盎司),您访问的属性可能会被擦除。如果希望事件永远不会放回池中,可以使用persist()方法。

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

第二个(async)将打印hasNative事件=false,因为事件属性已被清理。

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

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

您可以在这里测试这两种行为:JsFiddle

阅读Julen的答案,了解如何将persist()与节流/去盎司功能结合使用的示例。

 类似资料:
  • 问题内容: 如果应用程序是第一次加载,我正在尝试执行segue。我可以在调试器中看到我的打印消息,但是Perform Segue无法正常工作。我没有任何错误。有人可以告诉我怎么了吗? 问题答案: 您不能在viewDidLoad()中使用performSegue()。将其移动到viewDidAppear()。 在viewDidLoad()时,当前视图甚至还没有附加到窗口,因此尚无法进行隔离。

  • 问题内容: 我正在用PHP生成典型的Web 2.0 HTML页面:它包含许多标记和JavaScript代码,这些事件将在load事件之后实质上改变DOM。 有没有一种方法可以直接从PHP获取最终的HTML代码,而无需使用任何浏览器打开页面? 例如,假设页面的HTML是(仅作为示例): 该HTML保存在PHP变量中。现在,我想将该变量传递给某个函数,该函数将返回$ result = 。 这可能吗?

  • 我有一个四列DataFrame,其中有两列标记化的单词,这些单词已经删除并转换为小写,现在正试图阻止。 我不确定如果方法访问系列加上它的单个单元格,或者如果我需要另一种方式进入每个记录,所以尝试了两者(我想!) --------------------------------------------------------------------------- TypeError Tracebac

  • 在这里,我想在按下按钮时执行一个操作,这很容易,但主要问题是在扩展的JPanel中执行。可能有一个简单的解决方案,比如向特定的按钮添加动作监听器并调用actionperformed事件,但我的案例不是这样的,我有4个按钮(t1、t2、t3、t4)。所有这些按钮都将在单个actionperformed事件ae中运行(查看代码段)。稍后您可以看到调用另一个JButtons tr和rf调用actionl

  • 我已经定义了partitioner类,它返回与网格大小相同的executionContext。执行上下文={part3=start=0,part1=start=0,part2=start=0} 日志:-

  • 问题内容: 在提交表单时,我正在尝试取代默认的发布行为。 显然,在React中,onSubmit是表单支持的事件。但是,当我尝试以下代码时: 该方法已运行,但是此后仍执行默认的发布行为。 您可以在我的jsfiddle中进行测试。 我的问题:如何防止默认的发布行为? 问题答案: 在您的函数中,传递事件并使用。