React中使用RTK Query调用Google Books API的无默认值适配问题
解决方案
核心思路
你的问题本质是需要控制RTK Query的请求触发时机,默认不发起请求,仅在用户输入有效关键词并点击搜索后才调用API。不需要改用Mutation,Query完全能满足需求,核心是利用RTK Query的skip参数或者拆分状态来控制请求触发。
方案一:使用skip参数阻止初始请求
这是最简洁的方案,通过skip选项让Query在关键词为空时跳过请求。
1. 修改主组件初始状态
将默认搜索词设为空:
const BookFinder = () => { const [searchTerm, setSearchTerm] = useState(''); // 初始为空 return ( <> <Container> <Row className='mt-5'> <h1>Book Finder</h1> <SearchBar {...{searchTerm, setSearchTerm}}/> </Row> <Row xs={2} md={4} className='g-5 mt-3'> <BookList {...{searchTerm}} /> </Row> </Container> </> ); }
2. 调整SearchBar的占位符
把占位符改为固定提示,避免初始为空时无提示:
const SearchBar = ({ searchTerm, setSearchTerm }) => { const searchBar = useRef() return ( <> <InputGroup className="mb-3 pt-3"> <Form.Control placeholder="输入书名搜索" // 替换为固定提示 aria-label="Search" aria-describedby="search" ref={searchBar} /> <Button variant="outline-primary" id="search" onClick={() => setSearchTerm(searchBar.current.value.trim())}> <FontAwesomeIcon icon={faMagnifyingGlass} /> </Button> </InputGroup> </> ); }
3. 在BookList中添加skip控制
当关键词为空时跳过请求,同时增加初始状态的提示:
import { useGetBooksQuery } from '../../services/bookSlice'; const BookList = ({ searchTerm }) => { // 关键词为空时跳过API请求 const { data: books, isLoading, isSuccess, isError, error } = useGetBooksQuery(searchTerm, { skip: !searchTerm.trim() }) // 初始状态(无搜索词)返回提示 if (!searchTerm.trim()) { return <div>请输入书名进行搜索</div> } if(isLoading) { return ( <div className="d-flex align-items-center justify-content-center"> <strong>Loading...</strong> <div className="spinner-border" role="status" aria-hidden="true"></div> </div> ) } if(isError) { return <div>{error.toString()}</div> } if(isSuccess) { const { items } = books || {}; return items ? ( // 这里写你的书籍列表渲染逻辑 items.map(book => <div key={book.id}>{book.volumeInfo.title}</div>) ) : ( <div>未找到相关书籍</div> ); } return null; }
方案二:拆分状态(更严谨)
如果需要更严格控制搜索触发时机(比如避免用户输入空字符后误触发),可以拆分输入框状态和实际搜索状态:
1. 修改主组件状态
新增独立的搜索触发状态:
const BookFinder = () => { const [inputValue, setInputValue] = useState(''); // 输入框实时值 const [currentSearchTerm, setCurrentSearchTerm] = useState(''); // 实际触发搜索的关键词 const handleSearch = () => { const trimmedValue = inputValue.trim(); setCurrentSearchTerm(trimmedValue); } return ( <> <Container> <Row className='mt-5'> <h1>Book Finder</h1> <SearchBar inputValue={inputValue} setInputValue={setInputValue} onSearch={handleSearch} /> </Row> <Row xs={2} md={4} className='g-5 mt-3'> <BookList searchTerm={currentSearchTerm} /> </Row> </Container> </> ); }
2. 调整SearchBar组件
使用受控组件方式管理输入值:
const SearchBar = ({ inputValue, setInputValue, onSearch }) => { return ( <> <InputGroup className="mb-3 pt-3"> <Form.Control placeholder="输入书名搜索" aria-label="Search" aria-describedby="search" value={inputValue} onChange={(e) => setInputValue(e.target.value)} /> <Button variant="outline-primary" id="search" onClick={onSearch}> <FontAwesomeIcon icon={faMagnifyingGlass} /> </Button> </InputGroup> </> ); }
3. BookList组件逻辑不变
依然使用skip参数控制请求,和方案一的BookList代码一致。
关于Mutation的说明
不需要改用Mutation,因为你的场景是获取数据,RTK Query的Query专门用于这类只读请求;Mutation更多用于创建、更新、删除等修改数据的操作,用在这里反而不符合设计意图。
内容的提问来源于stack exchange,提问作者Avijit Majhi
相关产品推荐
相关产品推荐

