React应用调用Open Library API加载数据失败问题求助
问题排查与修复方案
1. 重复导入React及错误的StrictMode导入
你的App.js开头重复导入了React,而且strictMode的导入方式完全错误,这会导致编译警告甚至错误。直接删除第二行的导入语句:
// 删掉这行 import React, { strictMode } from 'react';
如果需要启用严格模式,在index.js里用<StrictMode>包裹App组件即可:
// index.js修改后 import React from 'react'; import ReactDOM from 'react-dom/client'; import './style.css'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <App /> </React.StrictMode> );
2. HTTP协议导致的混合内容错误
你用的是http://openlibrary.org的接口,但现在大多数React开发环境默认用HTTPS启动,浏览器会阻止HTTP请求从HTTPS页面发起,直接导致请求失败。把请求URL改成HTTPS:
fetch(`https://openlibrary.org/search.json?title=${searchTerm}`)
3. 未处理HTTP错误状态码
Fetch API只有在网络故障时才会触发catch,像404、500这类HTTP错误状态码不会自动进入catch,导致你看不到错误原因。需要在第一个then里检查响应状态:
const searchBooks = () => { fetch(`https://openlibrary.org/search.json?title=${searchTerm}`) .then((response) => { // 检查响应是否正常 if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then((data) => { const slicedBooks = data.docs.slice(0, 30); setBooks(slicedBooks); // 成功获取数据后清空错误状态 setError(null); }) .catch((error) => { console.error('Error:', error); setError('加载失败:' + error.message); }); };
4. 添加错误状态管理
你提到页面提示“error failed to load”,但代码里没有对应的错误展示逻辑。新增一个error状态来管理并显示错误信息:
// 在App组件里添加状态 const [error, setError] = useState(null); // 在return里添加错误展示 return ( <div> {/* 显示错误信息 */} {error && <div style={{color: 'red'}}>{error}</div>} {/* 原有的搜索栏、表格、详情部分 */} <div> <input type="text" value={searchTerm} onChange={handleInputChange} /> <button onClick={searchBooks}>Search</button> </div> // ... 其余代码不变 </div> );
完整修改后的App.js代码
import React, { useState } from 'react'; function App() { const [searchTerm, setSearchTerm] = useState(''); const [books, setBooks] = useState([]); const [selectedBook, setSelectedBook] = useState(null); const [error, setError] = useState(null); const handleInputChange = (event) => { setSearchTerm(event.target.value); }; const searchBooks = () => { // 清空之前的错误和书籍列表 setError(null); setBooks([]); setSelectedBook(null); fetch(`https://openlibrary.org/search.json?title=${searchTerm}`) .then((response) => { if (!response.ok) { throw new Error(`请求失败,状态码:${response.status}`); } return response.json(); }) .then((data) => { const slicedBooks = data.docs.slice(0, 30); setBooks(slicedBooks); }) .catch((error) => { console.error('Error:', error); setError('加载失败:' + error.message); }); }; const showBookDetails = (book) => { setSelectedBook(book); }; return ( <div> {error && <div style={{ color: 'crimson', margin: '10px 0' }}>{error}</div>} <div style={{ margin: '10px 0' }}> <input type="text" value={searchTerm} onChange={handleInputChange} placeholder="输入书名搜索" style={{ padding: '6px', width: '250px' }} /> <button onClick={searchBooks} style={{ padding: '6px 12px', marginLeft: '8px' }} > Search </button> </div> <table style={{ borderCollapse: 'collapse', width: '80%' }}> <thead> <tr style={{ backgroundColor: '#f0f0f0' }}> <th style={{ border: '1px solid #ddd', padding: '8px' }}>Author</th> <th style={{ border: '1px solid #ddd', padding: '8px' }}>Title</th> <th style={{ border: '1px solid #ddd', padding: '8px' }}>First Publish Year</th> </tr> </thead> <tbody> {books.map((book) => ( <tr key={book.key} onClick={() => showBookDetails(book)} style={{ cursor: 'pointer', borderBottom: '1px solid #ddd' }} > <td style={{ border: '1px solid #ddd', padding: '8px' }}>{book.author_name ? book.author_name[0] : 'Unknown'}</td> <td style={{ border: '1px solid #ddd', padding: '8px' }}>{book.title}</td> <td style={{ border: '1px solid #ddd', padding: '8px' }}>{book.first_publish_year}</td> </tr> ))} </tbody> </table> {selectedBook && ( <div style={{ margin: '20px 0', padding: '15px', border: '1px solid #ddd', borderRadius: '4px', width: '80%' }}> <h2>Book Details</h2> <p> <strong>Title:</strong> {selectedBook.title} </p> {selectedBook.author_name && ( <p> <strong>Author:</strong> {selectedBook.author_name.join(', ')} </p> )} {selectedBook.publisher && ( <p> <strong>Publisher:</strong> {selectedBook.publisher.join(', ')} </p> )} {selectedBook.language && ( <p> <strong>Language:</strong> {selectedBook.language.join(', ')} </p> )} {selectedBook.subject && ( <p> <strong>Subjects:</strong> {selectedBook.subject.join(', ')} </p> )} </div> )} </div> ); } export default App;
内容的提问来源于stack exchange,提问作者SterlinkArcher
相关产品推荐
相关产品推荐

