我有一个主页,该页面从GET调用(使用axios)加载书卡(带有书本图像,书名等),我正在使用redux
操作调用程序来触发API调用“ getAllBooks”在componentDidMount()
上。我还使用react-router
Link
组件将书与“ id”链接,一旦用户单击书证,他将被带到BookView页面,该ID取自this.props.match.params
。 BookView组件使用另一个操作调用程序(位于上一个操作调用程序的同一文件中,并且共享相同的reducer)加载API调用以获取“ bookById”。
当我从BookView页面返回主页时(使用浏览器的后退按钮或使用this.props.history.goBack()
),会出现问题。返回到HomeView时,状态将被“ BookByID”操作覆盖,并且我无法恢复到旧状态(因此,在主页上出现undefined
错误)。
我尝试将操作放入不同的文件中(当然这是没有用的,因为我对两个操作都使用了相同的reducer)。我尝试在首页上设置componentDidUpdate
来在道具不匹配时触发动作。尝试将动作分派到(该reduce的)redux状态以将其重置,但没有任何效果。我不确定自己犯了什么错误,请足够友好地指导我解决问题。
为此,我正在使用React 16.8和Redux 7.1(以及Thunk来帮助异步调用)。
Home.js
import { getBooks, resetGetBooks } from "../../redux/actions/bookDbAction";
class Home extends Component {
constructor(props) {
super(props);
this.signal = true;
this.titleInput = React.createRef();
this.descriptionInput = React.createRef();
this.isbnInput = React.createRef();
this.isbn13Input = React.createRef();
this.grIdInput = React.createRef();
this.imgLinkLargeInput = React.createRef();
this.imgLinkMediumInput = React.createRef();
this.imgLinkSmallInput = React.createRef();
}
componentDidMount() {
this.props.getBooks();
}
// when component re-renders
// componentDidUpdate(prevProps, prevState) {
// if(prevProps.books !== this.props.books) {
// this.props.getBooks();
// }
// }
renderBooks() {
const { classes, books, loading, error } = this.props;
if (loading) {
return (
<div className={classes.progressWrapper}>
<CircularProgress />
</div>
);
}
if (books.length === 0) {
return (
<Typography className={classes.noResults} variant="h4">
There are no books available
</Typography>
);
}
return (
<Grid container spacing={3}>
{books.map(book => (
<Grid item key={book.id} lg={2} md={4} xs={6}>
<Link className={classes.link} to={`/book/${book.id}`}>
<BookCardGrid book={book} />
</Link>
</Grid>
))}
</Grid>
);
}
render() {
const { classes } = this.props;
return (
<CoreLayout title="Home">
<div className={classes.root}>
<BookToolbar />
<div className={classes.content}>{this.renderBooks()}</div>
<div className={classes.pagination}>
<Typography variant="caption">1-6 of 20</Typography>
<IconButton>
<ChevronLeftIcon />
</IconButton>
<IconButton>
<ChevronRightIcon />
</IconButton>
</div>
</div>
</CoreLayout>
);
}
}
const mapStateToProps = state => {
return {
books: state.book.data,
loading: state.book.dataLoading,
error: state.book.error
};
};
const mapDispatchToProps = {
getBooks,
resetGetBooks
};
Home.defaultProps = {
books: [],
loading: true,
error: ""
};
Home.propTypes = {
classes: PropTypes.object.isRequired,
books: PropTypes.array.isRequired,
loading: PropTypes.bool.isRequired,
error: PropTypes.string.isRequired
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withStyles(styles)(Home));
Book.js <---这是BookView页面
import { getBookById, resetGetBookById } from "../../redux/actions/bookDbAction";
class Book extends Component {
constructor(props) {
super(props);
this.signal = true;
this.state = {
isLoading: false,
book: {
bookTitle: "",
description: "",
isbn: "",
isbn13: "",
grId: "",
imgLinkLarge: "",
imgLinkMedium: "",
imgLinkSmall: ""
},
error: null
};
}
componentDidMount() {
const { id } = this.props.match.params;
this.props.getBookById(id);
}
componentWillUnmount() {
this.props.resetGetBookById();
}
goBack = () => {
this.props.history.goBack();
};
render() {
const { classes, book, loading, error } = this.props;
return (
<CoreLayout title={book.title}>
<div className={classes.root}>
<IconButton
className={classes.iconButton}
onClick={this.goBack}
size="medium"
>
<BackIcon fontSize="medium" />
</IconButton>
{loading ? (
<div className={classes.progressWrapper}>
<CircularProgress />
</div>
) : (
<div className={classes.content}>
<div className={classes.imageWrapper + " image-wrap"}>
<img
alt={book.title}
className={classes.image}
src={book.img_m}
/>
</div>
</div>
)}
</div>
</CoreLayout>
);
}
}
Book.propTypes = {
classes: PropTypes.object.isRequired
};
Book.defaultProps = {
books: [],
loading: true,
error: ""
};
const mapStateToProps = state => {
return {
book: state.book.data,
loading: state.book.dataLoading,
error: state.book.error
};
};
const mapDispatchToProps = {
getBookById,
resetGetBookById
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withStyles(styles)(Book));
BookDbAction.js <---这是具有所有动作创建者的Book动作文件
import {
GET_ALL_BOOKS_PENDING,
GET_ALL_BOOKS_SUCCESS,
GET_ALL_BOOKS_FAILURE,
GET_ALL_BOOKS_RESET,
GET_BOOK_BY_ID_PENDING,
GET_BOOK_BY_ID_SUCCESS,
GET_BOOK_BY_ID_FAILURE,
GET_BOOK_BY_ID_RESET
} from "./types";
import axios from "axios";
const URL = `${process.env.REACT_APP_DEVELOPMENT_SERVER_URL}/book`;
export const getBooksPending = () => ({
type: GET_ALL_BOOKS_PENDING,
dataLoading: true
});
export const getBooksSuccess = json => ({
type: GET_ALL_BOOKS_SUCCESS,
dataLoading: false,
payload: json
});
export const getBooksFailure = error => ({
type: GET_ALL_BOOKS_FAILURE,
dataLoading: false,
payload: error
});
export const getBooksReset = () => ({
type: GET_ALL_BOOKS_RESET
});
export const getBooks = () => {
return async dispatch => {
try {
let response = await axios.get(URL);
dispatch(getBooksPending());
let data = await response.data;
dispatch(getBooksSuccess(data));
} catch (error) {
console.log(error);
dispatch(getBooksFailure(error));
}
};
};
export const resetGetBooks = () => {
return dispatch => {
dispatch(getBooksReset());
};
};
export const getBookByIdPending = () => ({
type: GET_BOOK_BY_ID_PENDING,
dataLoading: true
});
export const getBookByIdSuccess = json => ({
type: GET_BOOK_BY_ID_SUCCESS,
dataLoading: false,
payload: json
});
export const getBookByIdFailure = error => ({
type: GET_BOOK_BY_ID_FAILURE,
dataLoading: false,
payload: error
});
export const getBookByIdReset = () => ({
type: GET_BOOK_BY_ID_RESET
});
export const getBookById = id => {
return async dispatch => {
try {
let response = await axios.get(`${URL}/${id}`);
dispatch(getBookByIdPending());
let json = await response.data;
dispatch(getBookByIdSuccess(json));
} catch (error) {
dispatch(getBookByIdFailure(error));
}
};
};
export const resetGetBookById = () => {
return dispatch => {
dispatch(getBookByIdReset());
};
};
export const addBookPending = () => ({
type: ADD_BOOK_PENDING,
dataLoading: true
});
export const addBookSuccess = data => ({
type: ADD_BOOK_SUCCESS,
dataLoading: false,
payload: data
});
export const addBookFailure = error => ({
type: ADD_BOOK_FAILURE,
dataLoading: false,
payload: error
});
export const addBookReset = () => ({
type: ADD_BOOK_RESET
});
export const addBook = data => {
return async dispatch => {
try {
let response = await axios.post(`${URL}`, {
grid: data.grId,
title: data.bookTitle,
descr: data.description,
isbn: data.isbn,
isbn13: data.isbn13,
img_l: data.imgLinkLarge,
img_m: data.imgLinkMedium,
img_s: data.imgLinkSmall
});
dispatch(addBookPending());
let id = await response.data;
const data = { id, ...data };
// console.log("res:" + JSON.stringify(response));
// console.log("id:" + id);
dispatch(addBookSuccess(data));
} catch (error) {
dispatch(addBookFailure(error));
}
};
};
export const resetaddBook = () => {
return dispatch => {
dispatch(addBookReset());
};
};
b> BookDbReducer.js <---这是Book reducer文件
import {
GET_ALL_BOOKS_PENDING,
GET_ALL_BOOKS_SUCCESS,
GET_ALL_BOOKS_FAILURE,
GET_BOOK_BY_ID_PENDING,
GET_BOOK_BY_ID_SUCCESS,
GET_BOOK_BY_ID_FAILURE,
GET_BOOK_BY_ID_RESET
} from "../actions/types";
const initialState = {
dataLoading: true,
data: [],
error: ""
};
const bookDbReducer = (state = initialState, action) => {
switch (action.type) {
case GET_ALL_BOOKS_PENDING:
return {
...state,
dataLoading: action.dataLoading
};
case GET_ALL_BOOKS_SUCCESS:
return {
...state,
dataLoading: action.dataLoading,
data: action.payload
};
case GET_ALL_BOOKS_FAILURE:
return {
...state,
dataLoading: action.dataLoading,
error: action.payload
};
case GET_BOOK_BY_ID_PENDING:
return {
...state,
dataLoading: action.dataLoading
};
case GET_BOOK_BY_ID_SUCCESS:
return {
...state,
dataLoading: action.dataLoading,
data: action.payload
};
case GET_BOOK_BY_ID_FAILURE:
return {
...state,
dataLoading: action.dataLoading,
error: action.payload
};
case GET_BOOK_BY_ID_RESET:
return {
...state,
dataLoading: false,
data: null,
error: null
};
default:
return state;
}
};
export default bookDbReducer;
答案 0 :(得分:0)
您应该尝试将书籍详细信息数据存储在另一个商店属性中。这样一来,将保留一系列书籍。
const initialState = {
dataLoading: true,
data: [],
bookDetails: {},
error: ""
};
case GET_BOOK_BY_ID_SUCCESS:
return {
...state,
dataLoading: action.dataLoading,
bookDetails: action.payload
};