当我点击书籍推荐时,我正在工作。它带我到一个名为“书”的新组件。并显示该单书详细信息。但仅当条件正在运行并显示 te 加载时。 我不明白如何解决这个问题。这是我的代码。
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom'; // Import useNavigate instead of useHistory
import { useDispatch, useSelector } from 'react-redux';
import MenuAppBar from './components/MenuAppBar';
import './Home.css';
import { Search, onSubmit,SingleBookDetails,setSelectedBookId } from './Redux/actions';
import Autocomplete from '@mui/material/Autocomplete';
import TextField from '@mui/material/TextField';
import SingleBook from './components/Book'; // Make sure the path is correct
const Main = () => {
const dispatch = useDispatch();
const searchQuery = useSelector((state) => state.search);
const apiResponse = useSelector((state) => state.apiResponse);
const BookList = useSelector((state) => state.BookList);
const selectedBookId = useSelector((state) => state.selectedBookId);
const [inputValue, setInputValue] = useState('');
const [selectedBook, setSelectedBook] = useState(null);
const navigate = useNavigate(); // Use useNavigate instead of useHistory
const handleSearchChange = (value) => {
setInputValue(value);
dispatch(Search(value));
};
const handleFormSubmit = (value) => {
dispatch(onSubmit(value));
};
const handleBookClick = (book) => {
console.log('Clicked book:', book);
setSelectedBook(book);
// Navigate to the book details page
dispatch(SingleBookDetails(book.id[0]._));
navigate(`/book-details/${book.id[0]._}`);
};
console.log('BookList', BookList);
return (
<>
{/* <BookDetails /> */}
<div className="home-container">
<MenuAppBar />
<div className="centered-search-container">
<Autocomplete
freeSolo
id="combo-box-demo"
options={apiResponse || []}
getOptionLabel={(option) => option.best_book[0].title[0]}
sx={{
width: 300,
backgroundColor: '#FFFFFF',
borderRadius: '8px',
boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)',
}}
onInputChange={(event, newInputValue) => {
handleSearchChange(newInputValue);
}}
onChange={(event, newValue) => {
// Handle book selection here
if (newValue) {
handleBookClick(newValue);
}
}}
renderInput={(params) => <TextField {...params} label="Search Books" />}
/>
<button
style={{
marginLeft: '10px',
padding: '10px',
backgroundColor: '#00695C',
color: 'white',
}}
onClick={() => handleFormSubmit(inputValue)}
>
Search
</button>
</div>
</div>
{/* Render the BookDetails component when a book is selected */}
{/* {selectedBook && <Single bookDetails={selectedBook} />} */}
{selectedBookId && <SingleBook />}
</>
);
};
export default Main;
我的操作文件
import { parseString } from 'xml2js';
export const Search = (query) => (dispatch) => {
console.log('Dispatching Search_Query action with payload:', query);
console.log('Search Query in Redux Action:', query);
dispatch({
type: 'SET_SEARCH_QUERY',
payload: query,
});
};
export const onSubmit = (inputValue) => async (dispatch) => {
try {
// Dispatch the initial action
dispatch({
type: 'ON_SUBMIT',
payload: inputValue,
});
console.log('Submitting query...', inputValue);
const apiKey = 'rgMebNe9PaPTpob7TImEw';
const response = await fetch(`https://www.goodreads.com/search/index.xml?key=${apiKey}&q=${inputValue}`);
const xmlData = await response.text();
// Convert XML to JSON using xml2js
parseString(xmlData, (err, result) => {
const bookData = result?.GoodreadsResponse?.search?.[0]?.results?.[0]?.work;
console.log('Book Data:', bookData);
// console.log('Dispatching HANDLE_API_RESPONSE action with payload:', bookData);
dispatch({
type: 'HANDLE_API_RESPONSE',
payload: bookData,
});
});
} catch (error) {
console.error('Error submitting query:', error.message);
// Handle the error as needed
dispatch({
type: 'HANDLE_API_ERROR',
payload: error.message,
});
}
};
export const setSelectedBookId = (bookId) => ({
type: 'SET_SELECTED_BOOK_ID',
payload: bookId,
});
export const SingleBookDetails = (bookId) => async (dispatch) => {
try {
const apiKey = 'rgMebNe9PaPTpob7TImEw';
const response = await fetch(`https://www.goodreads.com/book/show/${bookId}.xml?key=${apiKey}`);
const xmlData = await response.text();
console.log('XML Data:', xmlData);
// Convert XML to JSON using xml2js
parseString(xmlData, (err, result) => {
const bookDetails = result?.GoodreadsResponse?.book?.[0];
console.log('Book Details:', bookDetails);
dispatch({
type: 'FETCH_BOOK_DETAILS_SUCCESS',
payload: { id: bookId, data: bookDetails },
});
});
} catch (error) {
console.error('Error fetching book details:', error.message);
dispatch({
type: 'FETCH_BOOK_DETAILS_FAILURE',
payload: error.message,
});
}
};
我的书籍文件。该文件仅显示 if 条件:
import React from 'react';
import { useSelector } from 'react-redux';
const SingleBook = () => {
// Use useSelector to get state from the Redux store
const selectedBookId = useSelector((state) => state.selectedBookId);
const bookDetails = useSelector((state) => state.bookDetails[selectedBookId]);
console.log('Selected Book ID:', selectedBookId);
console.log('BookDetailsssss:', bookDetails);
if (!bookDetails) {
return <div>Loading...!!!</div>;
}
const book = bookDetails.work[0];
console.log('Bookeeeeee:', book);
const title = book.original_title[0];
const author = book.authors[0].author[0].name[0];
const averageRating = book.average_rating[0];
const ratingsCount = book.ratings_count[0];
const imageUrl = book.small_image_url[0];
const description = book.description[0];
const link = book.link[0];
return (
<div>
<h1>{title}</h1>
<p>Author: {author}</p>
<p>Average Rating: {averageRating}</p>
<p>Ratings Count: {ratingsCount}</p>
<img src={imageUrl} alt={title} />
<p>Description: {description}</p>
<p>
<a href={link} target="_blank" rel="noopener noreferrer">
More Details on Goodreads
</a>
</p>
</div>
);
};
export default SingleBook;
这是我的减速器文件。
const initialState = {
search: null,
submittedValue: null,
bookList:[],
bookDetails:[],
apiResponse: [],
error: null,
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'SET_SEARCH_QUERY':
return {
...state,
search: action.payload,
};
case 'ON_SUBMIT':
console.log('Form submitted!');
return {
...state,
submittedValue: action.payload,
};
case 'SET_SELECTED_BOOK_ID':
return {
...state,
selectedBookId: action.payload,
};
case 'HANDLE_API_RESPONSE':
console.log('API Response:', action.payload);
// Extract book names from the API response
const bookData = action.payload || [];
const BookList = bookData.map(book => ({
id: book.id[0]._,
title: book.best_book[0].title[0],
author: book.best_book[0].author[0].name[0],
}));
return {
...state,
apiResponse:bookData,
BookList: BookList,
error: null,
};
case 'HANDLE_API_ERROR':
console.error('API Error:', action.payload);
return {
...state,
error: action.payload,
};
case 'FETCH_BOOK_DETAILS_SUCCESS':
return {
...state,
bookDetails: {
...state.bookDetails,
[action.payload.id]: action.payload.data,
},
error: null,
};
case 'FETCH_BOOK_DETAILS_FAILURE':
return {
...state,
error: action.payload,
};
default:
return state;
}
};
export default reducer;
我尝试在不调用selectorbookId的情况下执行此操作,但它不起作用并给出
cannot read properties of reading 0
的错误。我期望当我单击特定书籍时,它将在书籍组件中显示单本书的详细信息。
在 Main 组件中,您将调度 SingleBookDetails 操作来获取书籍详细信息,并使用
selectedBookId
有条件地呈现 SingleBook 组件。单击一本书时,您不会调度 setSelectedBookId
操作。