You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 13:52:47