2019: try hooks + promise debouncing(2019:尝试钩子+承诺反跳)
This is the most up to date version of how I would solve this problem.
(这是我如何解决此问题的最新版本。)
I would use:(我会用:)
This is some initial wiring but you are composing primitive blocks on your own, and you can make your own custom hook so that you only need to do this once.
(这是一些初始接线,但是您可以自己构成基本块,并且可以制作自己的自定义钩子,因此只需执行一次即可。)
const useSearchStarwarsHero = () => {
// Handle the input text state
const [inputText, setInputText] = useState('');
// Debounce the original search async function
const debouncedSearchStarwarsHero = useConstant(() =>
AwesomeDebouncePromise(searchStarwarsHero, 300)
);
const search = useAsync(
async () => {
if (inputText.length === 0) {
return [];
} else {
return debouncedSearchStarwarsHero(inputText);
}
},
// Ensure a new request is made everytime the text changes (even if it's debounced)
[inputText]
);
// Return everything needed for the hook consumer
return {
inputText,
setInputText,
search,
};
};
And then you can use your hook:
(然后可以使用您的钩子:)
const SearchStarwarsHeroExample = () => {
const { inputText, setInputText, search } = useSearchStarwarsHero();
return (
<div>
<input value={inputText} onChange={e => setInputText(e.target.value)} />
<div>
{search.loading && <div>...</div>}
{search.error && <div>Error: {search.error.message}</div>}
{search.result && (
<div>
<div>Results: {search.result.length}</div>
<ul>
{search.result.map(hero => (
<li key={hero.name}>{hero.name}</li>
))}
</ul>
</div>
)}
</div>
</div>
);
};
You will find this example running here and you should read react-async-hook documentation for more details.
(您将发现此示例在此处运行,并且您应该阅读react-async-hook文档以获取更多详细信息。)
2018: try promise debouncing(2018年:尝试Promise反弹)
We often want to debounce API calls to avoid flooding the backend with useless requests.
(我们通常希望对API调用进行去抖动,以避免后端无用的请求泛滥。)
In 2018, working with callbacks (Lodash/Underscore) feels bad and error-prone to me.
(在2018年,使用回调(Lodash / Underscore)感到糟糕并且容易出错。)
It's easy to encounter boilerplate and concurrency issues due to API calls resolving in an arbitrary order.(由于API调用以任意顺序进行解析,因此很容易遇到样板和并发问题。)
I've created a little library with React in mind to solve your pains: awesome-debounce-promise .
(我已经创建了一个小库来考虑React的问题: awesome-debounce-promise 。)
This should not be more complicated than that:
(这不应该比这更复杂:)
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 });
};
}
The debounced function ensures that:
(去抖动功能可确保:)
Eventually, you may add another trick if your component unmounts:
(最终,如果卸载了组件,您可能会添加另一个技巧:)
componentWillUnmount() {
this.setState = () => {};
}
Note that Observables (RxJS) can also be a great fit for debouncing inputs, but it's a more powerful abstraction which may be harder to learn/use correctly.
(请注意, Observables (RxJS)也可以非常适合去抖动输入,但是它是更强大的抽象,可能更难于正确学习/使用。)
< 2017: still want to use callback debouncing?(<2017:仍要使用回调反跳吗?)
The important part here is to create a single debounced (or throttled) function per component instance .
(这里的重要部分是为每个组件实例创建一个单独的去抖动(或抑制)功能 。)
You don't want to recreate the debounce (or throttle) function everytime, and you don't want either multiple instances to share the same debounced function.(您不想每次都重新创建去抖动(或调节)功能,也不想多个实例共享相同的去抖动功能。)
I'm not defining a debouncing function in this answer as it's not really relevant, but this answer will work perfectly fine with _.debounce
of underscore or lodash, as well as any user-provided debouncing function.
(我不会在这个答案定义防抖动功能,因为它不是真正相关的,但这个答案将与完美的罚款_.debounce
下划线或lodash的,以及任何用户提供防抖动功能。)
GOOD IDEA:(好主意:)
Because debounced functions are stateful, we have to create one debounced function per component instance .
(因为去抖功能是有状态的,所以我们必须为每个组件实例创建一个去抖功能 。)
ES6 (class property) : recommended
(ES6(类属性) :推荐)
class SearchBox extends React.Component {
method = debounce(() => {
...
});
}
ES6 (class constructor)
(ES6(类构造函数))
class SearchBox extends React.Component {
constructor(props) {
super(props);
this.method = debounce(this.method.bind(this),1000);
}
method() { ... }
}
ES5
(ES5)
var SearchBox = React.createClass({
method: function() {...},
componentWillMount: function() {
this.method = debounce(this.method.bind(this),100);
},
});
See JsFiddle : 3 instances are producing 1 log entry per instance (that makes 3 globally).
(请参阅JsFiddle :3个实例每个实例产生1个日志条目(全局产生3个)。)
NOT a good idea:(这不是一个好主意:)
var SearchBox = React.createClass({
method: function() {...},
debouncedMethod: debounce(this.method, 100);
});
It won't work, because during class description object creation, this
is not the object created itself.
(它不起作用,因为在类描述对象创建期间, this
不是对象本身创建的。)
this.method
does not return what you expect because the this
context is not the object itself (which actually does not really exist yet BTW as it is just being created).(this.method
不会返回您期望的结果,因为this
上下文不是对象本身(实际上并没有真正存在,因为它只是被创建而已)。)
NOT a good idea:(这不是一个好主意:)
var SearchBox = React.createClass({
method: function() {...},
debouncedMethod: function() {
var debounced = debounce(this.method,100);
debounced();
},
});
This time you are effectively creating a debounced function that calls your this.method
.
(这次您实际上是在创建一个去抖动的函数,该函数调用您的this.method
。)
The problem is that you are recreating it on every debouncedMethod
call, so the newly created debounce function does not know anything about former calls!(问题是您在每个debouncedMethod
调用中都在重新创建它,因此新创建的debounce函数对以前的调用一无所知!)
You must reuse the same debounced function over time or the debouncing will not happen.(您必须随着时间的推移重复使用相同的防抖动功??能,否则防抖动将不会发生。)
NOT a good idea:(这不是一个好主意:)
var SearchBox = React.createClass({
debouncedMethod: debounce(function () {...},100),
});
This is a little bit tricky here.
(这有点棘手。)
All the mounted instances of the class will share the same debounced function, and most often this is not what you want!.
(该类的所有已安装实例将共享相同的去抖动功能,通常,这不是您想要的!)
See JsFiddle : 3 instances are producting only 1 log entry globally.(请参阅JsFiddle :3个实例在全球范围内仅产生1个日志条目。)
You have to create a debounced function for each component instance , and not a single debounced function at the class level, shared by each component instance.
(您必须为每个组件实例创建一个去抖动功能,而不是在每个类实例共享的类级别上创建一个单独的去抖动功能。)
<