gpt4 book ai didi

javascript - 当用户停止输入搜索框时执行 api 请求

转载 作者:行者123 更新时间:2023-12-04 08:02:21 26 4
gpt4 key购买 nike

我正在构建一个搜索字段,该字段根据用户输入从数据库中获取,但我遇到了一些困难。目前,它在每次击键时都获取数据,这并不理想。我查看了不同的答案,似乎最好的选择是在 componentDidUpdate() 中执行此操作,并通过 setTimeout() 获取输入感觉的引用以将其与当前值进行比较。

我已经试过了,但我仍然在每次击键时获取数据,不知道为什么?请参阅下面的组件示例:


class ItemsHolder extends Component {
componentDidMount() {
//ensures the page is reloaded at the top when routing
window.scrollTo(0, 0);
this.props.onFetchItems(this.props.search);
}

componentDidUpdate(prevProps, prevState) {
if (prevProps.search !== this.props.search) {
console.log(
this.props.search ===
this.props.searchRef.current.props.value.toUpperCase()
);
setTimeout(() => {
console.log(
this.props.search ===
this.props.searchRef.current.props.value.toUpperCase()
);
if (
this.props.search ===
this.props.searchRef.current.props.value.toUpperCase()
) {
this.props.onFetchItems(this.props.search, this.props.category);
}
}, 500);
}
}

我正在使用 Redux 进行状态管理。这是获取项目时调用的函数:

export const fetchItemsFromServer = (search) => {
return (dispatch) => {
dispatch(fetchItemsStart());
const query =
search.length === 0 ? '' : `?orderBy="country"&equalTo="${search}"`;
axios
.get('/items.json' + query)
.then((res) => {
const fetchedItems = [];
for (let item in res.data) {
fetchedItems.push({
...res.data[item],
id: item,
});
}
dispatch(fetchItemsSuccess(fetchedItems));
})
.catch((error) => {
dispatch(fetchItemsFail(error));
});
};
};

这就是我在搜索组件中设置 ref 的方式:

class Search extends Component {
constructor(props) {
super(props);
this.searchInput = React.createRef();
}
componentDidMount() {
this.props.onSetRef(this.searchInput);
}

render() {
return (
<Input
ref={this.searchInput}
toolbar
elementType={this.props.inputC.elementType}
elementConfig={this.props.inputC.elementConfig}
value={this.props.inputC.value}
changed={(event) => this.props.onChangedHandler(event)}
/>
);
}
}

根据教程,我发现这应该可行。供您引用,请参阅本教程中的代码。我不明白为什么上面的方法不起作用。唯一的区别是教程使用了钩子(Hook)。

const Search = React.memo(props => {
const { onLoadIngredients } = props;
const [enteredFilter, setEnteredFilter] = useState('');
const inputRef = useRef();

useEffect(() => {
const timer = setTimeout(() => {
if (enteredFilter === inputRef.current.value) {
const query =
enteredFilter.length === 0
? ''
: `?orderBy="title"&equalTo="${enteredFilter}"`;
fetch(
'https://react-hooks-update.firebaseio.com/ingredients.json' + query
)
.then(response => response.json())
.then(responseData => {
const loadedIngredients = [];
for (const key in responseData) {
loadedIngredients.push({
id: key,
title: responseData[key].title,
amount: responseData[key].amount
});
}
onLoadIngredients(loadedIngredients);
});
}
}, 500);
return () => {
clearTimeout(timer);
};
}, [enteredFilter, onLoadIngredients, inputRef]);

遵循 debounceInput 的建议:

import React, { Component } from 'react';
// import classes from './Search.css';
import Input from '../../UI/Input/Input';
// redux
import * as actions from '../../../store/actions/index';
import { connect } from 'react-redux';

class Search extends Component {
componentDidUpdate(prevProps, prevState) {
if (prevProps.search !== this.props.search) {
this.props.onFetchItems(this.props.search, this.props.category);
}
}

debounceInput = (fn, delay) => {
let timerId;
return (...args) => {
clearTimeout(timerId);
timerId = setTimeout(() => fn(...args), delay);
};
};

render() {
return (
<Input
toolbar
elementType={this.props.inputC.elementType}
elementConfig={this.props.inputC.elementConfig}
value={this.props.inputC.value}
changed={(event) =>
this.debounceInput(this.props.onChangedHandler(event), 500)
}
/>
);
}
}

const mapStateToProps = (state) => {
return {
inputC: state.filtersR.inputConfig,
search: state.filtersR.search,
};
};

const mapDispatchToProps = (dispatch) => {
return {
onChangedHandler: (event) => dispatch(actions.inputHandler(event)),
onFetchItems: (search, category) =>
dispatch(actions.fetchItemsFromServer(search, category)),
};
};

export default connect(mapStateToProps, mapDispatchToProps)(Search);

这里是得到帮助后的最终解决方案:

import React, { Component } from 'react';
// import classes from './Search.css';
import Input from '../../UI/Input/Input';
// redux
import * as actions from '../../../store/actions/index';
import { connect } from 'react-redux';

const debounceInput = (fn, delay) => {
let timerId;
return (...args) => {
clearTimeout(timerId);
timerId = setTimeout(() => fn(...args), delay);
};
};

class Search extends Component {
componentDidUpdate(prevProps, _prevState) {
if (prevProps.search !== this.props.search) {
this.responseHandler();
}
}

responseHandler = debounceInput(() => {
this.props.onFetchItems(this.props.search, this.props.category);
}, 1000);

render() {
return (
<Input
toolbar
elementType={this.props.inputC.elementType}
elementConfig={this.props.inputC.elementConfig}
value={this.props.inputC.value}
changed={(event) => this.props.onChangedHandler(event)}
/>
);
}
}

const mapStateToProps = (state) => {
return {
inputC: state.filtersR.inputConfig,
search: state.filtersR.search,
};
};

const mapDispatchToProps = (dispatch) => {
return {
onChangedHandler: (event) => dispatch(actions.inputHandler(event)),
onFetchItems: (search, category) =>
dispatch(actions.fetchItemsFromServer(search, category)),
};
};

export default connect(mapStateToProps, mapDispatchToProps)(Search);

最佳答案

您真的只需要去抖输入的 onChange 处理程序,或者更好的是,实际执行异步工作的函数。

非常简单的去抖动高阶函数:

const debounce = (fn, delay) => {
let timerId;
return (...args) => {
clearTimeout(timerId);
timerId = setTimeout(() => fn(...args), delay);
}
};

使用示例:

fetchData = debounce(() => fetch(.....).then(....), 500);

componentDidUpdate(.......) {
// input value different, call fetchData
}

<Input
toolbar
elementType={this.props.inputC.elementType}
elementConfig={this.props.inputC.elementConfig}
value={this.props.inputC.value}
changed={this.props.onChangedHandler}
/>

演示代码

Edit execute-api-request-when-user-stops-typing-search-box

const debounce = (fn, delay) => {
let timerId;
return (...args) => {
clearTimeout(timerId);
timerId = setTimeout(fn, delay, [...args]);
};
};

const fetch = (url, options) => {
console.log("Fetching", url);
return new Promise((resolve) => {
setTimeout(() => {
console.log("Fetch Resolved");
resolve(`response - ${Math.floor(Math.random() * 1000)}`);
}, 2000);
});
};

export default class App extends Component {
state = {
search: "",
response: ""
};

changeHandler = (e) => {
const { value } = e.target;
console.log("search", value);
this.setState({ search: value });
};

fetchData = debounce(() => {
const { search } = this.state;
const query = search.length ? `?orderBy="country"&equalTo="${search}"` : "";

fetch(
"https://react-hooks-update.firebaseio.com/ingredients.json" + query
).then((response) => this.setState({ response }));
}, 500);

componentDidUpdate(prevProps, prevState) {
if (prevState.search !== this.state.search) {
if (this.state.response) {
this.setState({ response: "" });
}
this.fetchData();
}
}

render() {
const { response, search } = this.state;
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>

<label>
Search
<input type="text" value={search} onChange={this.changeHandler} />
</label>

<div>Debounced Response: {response}</div>
</div>
);
}
}

关于javascript - 当用户停止输入搜索框时执行 api 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66394801/

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