【发布时间】:2021-05-29 08:44:53
【问题描述】:
我正在构建一个搜索字段,该字段根据用户输入从数据库中获取,我有点挣扎。目前,它在每次击键时都在获取数据,这并不理想。我查看了不同的答案,似乎最好的选择是在 componentDidUpdate() 中执行此操作并获取输入感觉的 ref 以通过 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)}
/>
);
}
}
根据教程,我发现这应该可行。供您参考,请参阅本教程中的代码。我不明白为什么上述方法不起作用。唯一的区别是本教程使用了钩子。
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);
【问题讨论】:
标签: javascript reactjs redux react-redux components