1.搜索组件的优化
先来回顾本来的搜索组件是怎么写的。
import React from 'react'
import classes from './FIlterMeals.module.css'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSearch } from '@fortawesome/free-solid-svg-icons'
export default function FilterMeals(props) {
const [keyword, setKeyWord] = React.useState('')
const inputChange = (event) => {
setKeyWord(event.target.value.trim())
//trim()去掉字符串中的空格trim() 只会去掉字符串开头和结尾的空格;
//props.filter(keyword)
const keyword = event.target.value
props.filter(keyword)
}
return (
<div className={classes.FilterMeals}>
<div className={classes.SearchBox}>
<FontAwesomeIcon className={classes.SearchIcon} icon={faSearch} />
<input value={keyword} onChange={Change} className={classes.SearchInput} type="text" name="" id="" placeholder={'请你输入内容'} />
</div>
</div>
)
}
我们直接去添加的监听事件,如果value变了那么就调用函数把输入的value当作keyword传过去,然后根组件里面筛选展示。
const filterHandle = (keyword) => {
const newHbb = originHbb.filter((item) => { return (item.title.includes(keyword)) })
// includes() 是否包含里面的字符串返回值truefalse和index Of()返回值 true 或 false 第一个匹配项的索引,找不到返回 -1
setHbb(newHbb)
}
· 但是这里我们希望用useEffect去监听value变化然后更新keyword,也就是把这个搜索组件变为受控组件。那么我们就需要去用useEffect书写代码。
const Change = (event) => {
setKeyWord(event.target.value)
}
React.useEffect(() => {
console.log('effect触发了');
props.filter(keyword)
}, [keyword])
这里keyword是用state设置的变量。然后我们用value={keyword}绑定输入框,用setKeyword(e.target.value)绑定state值。现在是受控组件,但是我们的组件还有一个问题。
输入一个h的时候就开始筛选了导致没东西展示???这很明显用户不能接受,这样我们要怎么做呢?也就是每次只要开始输入东西,就会重新筛选数据,
而且我们要知道useEffect可以发送请求拿回来数据的,我们这里只是学前端所以把数据放到根组件里面,但是实际上我们要发送请求拿回数据然后定义操作数据的函数。导致我们每次输入一个拼音就会发送请求??这显然不符合逻辑,会导致无数次访问服务器,甚至输入拼音的时候还会丢失列表。
我们就要去想我们怎么能在用户输出完之后去筛选呢?怎么判断用户输入完之后呢?
React.useEffect(() => {
//我们要降低数据过滤的次数,提高用户的体验
//用户输入完了再过滤用户输入的过程中不要过滤
//当用户停止输入1s后我们才去查询
setTimeout(() => {
console.log('effect触发了');
props.filter(keyword)
}, 1000)
}, [keyword])
这样我们好像给了用户一秒的输入时间,也就是说当keyword改变的时候,我们默认一秒用户输入时间,这样确实输入的时候拼音不会立马丢失了,但是服务器请求还是非常多次,这个问题没有解决反而更怪了。不仅调用非常多次而且还一秒后显示列表???
输入一个汉堡包调用这么多次真实离谱,我甚至开了Reacttool工具看起来更多了。那怎么去优化呢?
相当于还是hanbaobao一个拼音就调用一次。。。只不过筛选一秒后开始。。也就是说我们每次属于hanbaobao的时候每一次输入的字母比如我们输入h,计时器打开了,再次输入a,ha的计时器就打开了。。。所以每次输入新的都会重新再开启一个定时器。也就是说只要我们一直输入1s后肯定会出结果..
所以我们应该在开启一个定时器的时候,关闭上一个定时器,保证输入完之后才执行。
怎么关闭呢?这时候引出来我们钩子函数useEffect的另外一个功能,可以在回调函数中指定一个函数作为返回值,会在下一次执行effect前调用。这样我们就可以永远执行最新的输入内容计时器了。
先测试一下。
React.useEffect(() => {
console.log('effect触发了');
return (() => {
console.log('回调函数执行了');
}
}, [keyword])
确实是这样,那么我们就可以去执行删除前一个定时器了。
React.useEffect(() => {
const timer = setTimeout(() => {
console.log('effect触发了');
props.filter(keyword)
}, 1000)
return (() => {
console.log('回调函数执行了');
clearInterval(timer)
})
}, [keyword])
这样我们就实现了输入完之后1s才回去调用查询函数。优化完毕。
通过这个案例就可以更深入理解useEffect这个钩子函数了。