gpt4 book ai didi

javascript - Reactjs 和 redux - 如何防止来自实时搜索组件的过多 api 调用?

转载 作者:行者123 更新时间:2023-12-01 15:22:14 25 4
gpt4 key购买 nike

我创建了这个实时搜索组件:

class SearchEngine extends Component {
constructor (props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSearch = this.handleSearch.bind(this);
}
handleChange (e) {
this.props.handleInput(e.target.value); //Redux
}
handleSearch (input, token) {
this.props.handleSearch(input, token) //Redux
};
componentWillUpdate(nextProps) {
if(this.props.input !== nextProps.input){
this.handleSearch(nextProps.input, this.props.loginToken);
}
}
render () {
let data= this.props.result;
let searchResults = data.map(item=> {
return (
<div key={item.id}>
<h3>{item.title}</h3>
<hr />
<h4>by {item.artist}</h4>
<img alt={item.id} src={item.front_picture} />
</div>
)
});
}
return (
<div>
<input name='input'
type='text'
placeholder="Search..."
value={this.props.input}
onChange={this.handleChange} />
<button onClick={() => this.handleSearch(this.props.input, this.props.loginToken)}>
Go
</button>
<div className='search_results'>
{searchResults}
</div>
</div>
)
}

它是我正在开发的 React & Redux 应用程序的一部分,并已连接到 Redux 商店。
问题是,当用户输入搜索查询时,它会为输入中的每个字符触发 API 调用,并创建过多的 API 调用,从而导致显示先前查询结果等错误,而不是跟进当前搜索输入。

我的 api 调用(this.props.handleSearch):
export const handleSearch = (input, loginToken) => {
const API= `https://.../api/search/vector?query=${input}`;
}
return dispatch => {
fetch(API, {
headers: {
'Content-Type': 'application/json',
'Authorization': loginToken
}
}).then(res => {
if (!res.ok) {
throw Error(res.statusText);
}
return res;
}).then(res => res.json()).then(data => {
if(data.length === 0){
dispatch(handleResult('No items found.'));
}else{
dispatch(handleResult(data));
}
}).catch((error) => {
console.log(error);
});
}
};

我的意图是它将是实时搜索,并根据用户输入进行自我更新。但我试图找到一种方法来等待用户完成他的输入,然后应用更改以防止过多的 API 调用和错误。

建议?

编辑:

这对我有用。
感谢 Hammerbot's amazing answer我设法创建了自己的 QueueHandler 类。
export default class QueueHandler {

constructor () { // not passing any "queryFunction" parameter
this.requesting = false;
this.stack = [];
}

//instead of an "options" object I pass the api and the token for the "add" function.
//Using the options object caused errors.

add (api, token) {
if (this.stack.length < 2) {
return new Promise ((resolve, reject) => {
this.stack.push({
api,
token,
resolve,
reject
});
this.makeQuery()
})
}
return new Promise ((resolve, reject) => {
this.stack[1] = {
api,
token,
resolve,
reject
};
this.makeQuery()
})

}

makeQuery () {
if (! this.stack.length || this.requesting) {
return null
}

this.requesting = true;
// here I call fetch as a default with my api and token
fetch(this.stack[0].api, {
headers: {
'Content-Type': 'application/json',
'Authorization': this.stack[0].token
}
}).then(response => {
this.stack[0].resolve(response);
this.requesting = false;
this.stack.splice(0, 1);
this.makeQuery()
}).catch(error => {
this.stack[0].reject(error);
this.requesting = false;
this.stack.splice(0, 1);
this.makeQuery()
})
}
}

我做了一些更改,以便为我工作(见评论)。

我导入了它并分配了一个变量:
//searchActions.js file which contains my search related Redux actions

import QueueHandler from '../utils/QueueHandler';

let queue = new QueueHandler();

然后在我原来的 handleSearch 函数中:
export const handleSearch = (input, loginToken) => {
const API= `https://.../api/search/vector?query=${input}`;
}
return dispatch => {
queue.add(API, loginToken).then... //queue.add instead of fetch.

希望这对任何人都有帮助!

最佳答案

我认为它们是处理问题的几种策略。我将在这里讨论3种方式。

前两种方法是“节流”和“去抖动”您的输入。这里有一篇很好的文章解释了不同的技术:https://css-tricks.com/debouncing-throttling-explained-examples/

Debounce 等待给定的时间以实际执行您要执行的功能。如果在这个给定的时间内你打了同样的电话,它会再次等待这个给定的时间,看看你是否再次打电话。如果你不这样做,它将执行该功能。这张图片解释了这一点(取自上面提到的文章):

enter image description here

Throttle 直接执行该函数,等待给定时间等待新调用并执行在此给定时间内进行的最后一次调用。以下架构对其进行了解释(摘自这篇文章 http://artemdemo.me/blog/throttling-vs-debouncing/):

enter image description here

起初我使用的是第一种技术,但我发现它有一些缺点。主要问题是我无法真正控制组件的渲染。

让我们想象以下函数:

function makeApiCall () {
api.request({
url: '/api/foo',
method: 'get'
}).then(response => {
// Assign response data to some vars here
})
}

如您所见,请求使用异步过程,稍后将分配响应数据。现在让我们想象两个请求,我们总是想使用最后一个请求的结果。 (这就是您在搜索输入中想要的)。但是第二个请求的结果先于第一个请求的结果。这将导致您的数据包含错误的响应:
1. 0ms -> makeApiCall() -> 100ms -> assigns response to data
2. 10ms -> makeApiCall() -> 50ms -> assigns response to data

对我来说,解决方案是创建某种“队列”。这个队列的行为是:

1 - 如果我们将任务添加到队列中,该任务会排在队列的前面。
2 - 如果我们将第二个任务添加到队列中,该任务将进入第二个位置。
3 - 如果我们将第三个任务添加到队列中,该任务将替换第二个。

所以队列中最多有两个任务。一旦第一个任务结束,第二个任务就会执行等等......

所以你总是有相同的结果,并且你限制了你的 api 调用在许多参数的函数中。如果用户的网络连接速度较慢,第一个请求将需要一些时间来执行,因此不会有很多请求。

这是我用于此队列的代码:
export default class HttpQueue {

constructor (queryFunction) {
this.requesting = false
this.stack = []
this.queryFunction = queryFunction
}

add (options) {
if (this.stack.length < 2) {
return new Promise ((resolve, reject) => {
this.stack.push({
options,
resolve,
reject
})
this.makeQuery()
})
}
return new Promise ((resolve, reject) => {
this.stack[1] = {
options,
resolve,
reject
}
this.makeQuery()
})

}

makeQuery () {
if (! this.stack.length || this.requesting) {
return null
}

this.requesting = true

this.queryFunction(this.stack[0].options).then(response => {
this.stack[0].resolve(response)
this.requesting = false
this.stack.splice(0, 1)
this.makeQuery()
}).catch(error => {
this.stack[0].reject(error)
this.requesting = false
this.stack.splice(0, 1)
this.makeQuery()
})
}
}

你可以像这样使用它:
// First, you create a new HttpQueue and tell it what to use to make your api calls. In your case, that would be your "fetch()" function:

let queue = new HttpQueue(fetch)

// Then, you can add calls to the queue, and handle the response as you would have done it before:

queue.add(API, {
headers: {
'Content-Type': 'application/json',
'Authorization': loginToken
}
}).then(res => {
if (!res.ok) {
throw Error(res.statusText);
}
return res;
}).then(res => res.json()).then(data => {
if(data.length === 0){
dispatch(handleResult('No vinyls found.'));
}else{
dispatch(handleResult(data));
}
}).catch((error) => {
console.log(error);
});
}

关于javascript - Reactjs 和 redux - 如何防止来自实时搜索组件的过多 api 调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47238596/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com