输入框实时排序时字母回退导致顺序错乱怎么办?
我在做一个带搜索的列表,当用户输入字母实时过滤时,如果输入“apple”后回退到“app”,排序结果突然变得无序了,这是为什么?
用的是React,输入框绑定了 handleChange 事件,用数组的 filter 方法过滤数据,然后用自定义的排序函数。代码大概是这样的:
handleChange = (e) => {
const query = e.target.value.toLowerCase();
const filtered = items.filter(item =>
item.name.toLowerCase().includes(query)
);
this.setState({
results: filtered.sort((a,b) => {
return a.name.localeCompare(b.name, 'zh');
})
});
}
正常输入时排序没问题,但当删除最后一个字母时,列表突然按原始顺序排列了?比如输入a显示所有带a的条目按字母排序,继续输入p后继续排序,但删除到只剩ap时就乱了。试过把sort放在filter外面也没用,有没有可能跟setState的异步性有关?
localeCompare上,回退时可能因为字符集处理导致排序异常。我之前也踩过这坑,把排序函数改成稳妥的字符串比较就好。这样写稳得很,不会乱了顺序,赶紧试试吧,我先去睡会。
sort方法上。因为sort是原地排序,会直接修改原数组。当用户输入变化时,你每次用filter过滤的是原始items数组,而这个数组可能已经被排序过多次了,导致每次过滤后的顺序不一致。解决方法是:在每次过滤前,先复制一份原始数据再操作。这样能保证
items本身不会被污染。你可以改成这样:
这样每次过滤和排序都是基于一个干净的原始数组副本,不会影响到后续的逻辑。
另外你提到把
sort放到外面也没用,那是因为你可能没注意filter和sort都是会修改原数组的。特别是sort,如果不复制数组直接操作,会导致原始数据顺序被打乱。其实这个问题跟
setState的异步性关系不大,React 的setState虽然是异步的,但只要你在handleChange中操作的是不可变数据,就不会出现顺序错乱的问题。总结一下核心点:
1. 数组的
sort和filter都是原地修改的2. 每次操作前复制一份原始数组更安全
3. 保持数据流的纯净性很重要
你试试这样改,应该就能解决字母回退导致顺序错乱的问题了。