React搜索组件快速清空输入时searchResult状态未同步更新问题
问题根因
这是典型的异步请求竞态问题,触发逻辑如下:
- 当你输入非空内容时,会触发
BooksAPI.search异步请求,这个请求的响应速度受网络影响,不会立刻返回 - 你快速删除输入使内容为空时,会先执行逻辑把
searchResult设为空数组,但之前发出的旧搜索请求此时还没完成 - 等旧的搜索请求返回后,会再次执行
setState把searchResult覆盖为旧的搜索结果,就出现了query为空但searchResult没有同步清空的现象
另外你代码里存在两个小的隐患:
setState回调中判断的是原始输入的query,不是你存入state的trim()后的值,如果用户输入全空格,会出现state的query为空但依然触发搜索的问题- render方法中条件渲染部分有多余的闭合括号,可能引发语法报错
修复方案
核心修复:增加请求有效性校验
每次发起新搜索时标记当前的有效query,只有请求返回的query和当前有效query一致时,才更新搜索结果,避免旧请求覆盖新状态:
import React, { Component } from "react"; import { Link } from "react-router-dom"; import Book from "./Book"; import * as BooksAPI from "../BooksAPI"; export default class BookSearch extends Component { // 新增实例变量:记录当前有效的搜索query activeSearchQuery = ""; state = { query: "", searchResult: [], }; handleInputChange = (rawQuery) => { const trimmedQuery = rawQuery.trim(); this.setState( { query: trimmedQuery, }, () => { // 更新有效query标记,旧请求返回后会被判定无效 this.activeSearchQuery = trimmedQuery; if (trimmedQuery) { BooksAPI.search(trimmedQuery).then((books) => { // 只有返回结果对应的query和当前有效query一致时才更新状态 if (this.activeSearchQuery === trimmedQuery) { this.setState({ searchResult: books }); } }); } else { this.setState({ searchResult: [] }); } } ); }; // 组件卸载时清空标记,避免内存泄漏 componentWillUnmount() { this.activeSearchQuery = ""; } render() { const { query, searchResult } = this.state; const { updateBookShelves } = this.props; return ( <div className="search-books"> <div className="search-books-bar"> <Link to="/" className="close-search"> Close </Link> <div className="search-books-input-wrapper"> <input type="text" placeholder="Search by title or author" value={query} onChange={(event) => this.handleInputChange(event.target.value)} /> </div> </div> <div className="search-books-results"> <ol className="books-grid"> {searchResult.error ? ( <p>No results matching your search</p> ) : ( searchResult.map((book) => ( <Book key={book.id} book={book} updateBookShelves={updateBookShelves} /> )) )} </ol> </div> </div> ); } }
可选优化:增加防抖
可以给输入变更逻辑加300ms左右的防抖,减少频繁输入触发的无效API请求,进一步降低竞态出现的概率。
内容的提问来源于stack exchange,提问作者muhsen97
相关产品推荐
相关产品推荐

