(你可以看到我的声誉不是很高:) 我知道如果你不喜欢我的问题,这将是我的最后一个问题,因此我会尽可能地写它:)
我面临的问题类似于:
但是,上述问题的答案是使用“history.push”,这就是我正在做的事情,但我仍然遇到问题。
我在用:
- “反应”:“^16.0.0”
- “反应减少”:“^5.0.6”
- “反应路由器”:“^4.2.0”
- “反应路由器 dom”:“^4.2.2”
- “还原”:“^3.7.2”
- "redux-promise":"^0.5.3"
- “axios”:“^0.17.1”
我正在执行以下操作:
- 在反应组件“SearchText”中,获取文本字符串并调用动作创建者
- 在 action creator 中,使用文本字符串向 goodreads.com 发送 HTTP 请求
- 在我的 reducer 中,使用 action payload 设置 redux 状态
- 使用另一个组件“BookResults”(在另一个路由中)来显示此状态
组件“SearchText”有一个指向“BookResults”页面的链接。因此,一旦“SearchText”触发动作创建者,如果(当我在控制台上看到收到结果并且状态设置为书籍列表时)我单击路由到“BookResults”的链接,我看到书籍清单。
但是,如果“SearchText”使用(在触发动作创建者时)执行新页面的 history.push 的回调,并且此回调由 'axios(xxx).then' 调用,则状态设置不正确,尽管我在控制台中看到 HTTP 请求成功。
我相信你可以看到我做错了什么(我希望它不是很愚蠢)......请告诉我。
这是代码:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { createStore, applyMiddleware } from 'redux';
import ReduxPromise from 'redux-promise';
import SearchText from './components/search_text';
import BookResults from './components/book_results';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<BrowserRouter>
<div>
<BrowserRouter>
<Switch>
<Route path="/book_results" component={BookResults} />
<Route path="/" component={SearchText} />
</Switch>
</BrowserRouter>
</div>
</BrowserRouter>
</Provider>
, document.querySelector('#root'));
SearchText 组件
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Link } from 'react-router-dom';
import { searchForBooks } from '../actions';
class SearchText extends Component {
constructor(props) {
super(props);
this.state = {
searchText: ''
};
this.handleFormSubmit = this.handleFormSubmit.bind(this);
this.handleSearchTextChange = this.handleSearchTextChange.bind(this);
}
handleSearchTextChange(e) {
this.setState({ searchText: e.target.value });
}
handleFormSubmit(e) {
e.preventDefault();
const formPayload = {
searchText: this.state.searchText
};
console.log("In SearchBooks/handleFormSubmit. Submitting. state: ", this.state);
this.props.searchForBooks(formPayload, () => {
this.props.history.push(`/book_results`);
});
}
render() {
return (
<form className="container" onSubmit={this.handleFormSubmit}>
<h3>Search Form</h3>
<div className="form-group">
<label className="form-label">{'Search Text:'}</label>
<input
className='form-input'
type='text'
name='searchText'
value={this.state.searchText}
onChange={this.handleSearchTextChange}
onBlur={this.handleSearchTextBlur}
placeholder='' />
</div>
<br />
<input
type="submit"
className="btn btn-primary float-right"
value="Submit"/>
<br /><br />
<Link to={`/book_results`}>⇐ Book Results</Link>
</form>
);
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ searchForBooks: searchForBooks }, dispatch);
}
export default connect(null, mapDispatchToProps)(SearchText);
BookResults 组件
import React from 'react';
import { connect } from 'react-redux';
import _ from 'lodash';
import Book from './book';
class BookResults extends React.Component {
render() {
let books;
const booksArray = _.values(this.props.bookResults);
console.log("***In BookResults. booksArray: ", booksArray);
if (booksArray.length === 0) {
books = "No books to display";
} else {
books = booksArray.map( (book) => {
return (
<Book book={book} key={book.id} />
);
});
}
return (
<div>
<h2>Search Results</h2>
<br />
<ul>
{books}
</ul>
</div>
);
}
}
function mapStateToProps(state) {
return {
bookResults: state.bookResults,
cats: state.cats
};
}
export default connect(mapStateToProps)(BookResults);
图书组件
import React from 'react';
const Book = (props) => (
<li>
{props.book.title}
</li>
);
export default Book;
动作/index.js
如下所示,以下行被注释掉:
// .then(() => callback());
如果我包括它,我有问题。
import axios from 'axios';
export const SEARCH_FOR_BOOKS = 'search_for_books';
const GOODREADS = "https://www.goodreads.com/search/index.xml";
const KEY = "xxx";
export function searchForBooks(values, callback) {
let result;
console.log("In actions/searchForBooks. values: ", values);
if (!values.searchText || values.searchText === "") {
console.error("*** ERROR *** In actions/searchForBooks." +
"values.searchText: ", values.searchText);
} else {
const searchUrl = `${GOODREADS}?key=${KEY}&q=${values.searchText}`;
console.log("In actions/searchForBooks. url: " + searchUrl);
result = axios.get(searchUrl);
// .then(() => callback());
}
return {
type: SEARCH_FOR_BOOKS,
payload: result
};
}
减速器/index.js
import { combineReducers } from 'redux';
import bookResultsReducer from './reducer_book_results';
const rootReducer = combineReducers({
bookResults: bookResultsReducer
});
export default rootReducer;
减速机
import { parseString } from 'xml2js';
import _ from 'lodash';
import { SEARCH_FOR_BOOKS } from '../actions/index';
const bookResults = {};
export default function bookResultsReducer(state = bookResults, action) {
switch (action.type) {
case SEARCH_FOR_BOOKS:
console.log("In bookResultsReducer. payload: ", action.payload);
if (action.error) { // error from goodreads search books
console.error("*** APP ERROR *** In bookResultsReducer. action.error: ", action.error);
} else if (!action.payload || !action.payload.data) {
console.error("*** APP ERROR *** In bookResultsReducer." +
" action.payload or action.payload.data is undefined", action.payload);
} else {
parseString(action.payload.data, function(err, result) {
if (err) {
console.error("*** APP ERROR *** In bookResultsReducer. Error from parseString: ", err);
} else {
state = Object.assign({}, getBooks(result));
}
});
}
console.log("In bookResultsReducer. new state: ", state);
return state;
break;
default:
return state;
}
}
function getBooks(data) {
const bookResults = data.GoodreadsResponse.search[0].results[0].work;
if (!bookResults || bookResults.length === 0) {
return {};
} else {
const results = bookResults.map( (book, index) => {
const bookInfo = book.best_book[0];
return (
{ id: index + 1,
title: bookInfo.title[0] }
);
});
return _.mapKeys(results, 'id');
}
}