Ваша проблема очень похожа на этот вопрос (я также включил коды и коробку для игры).Пожалуйста, прочитайте его, следуйте рабочему примеру и, самое главное, прочитайте 7 советов (некоторые могут не относиться к вашему проекту; однако я настоятельно рекомендую установить prop-types
, чтобы предупредить вас, когда вы отклоняетесь от 1: 1избыточное состояние).
Проблема, с которой вы столкнулись, связана с тем, что эта функция postsFetchData
не возвращает обещание axios
(у вас также есть ненужный .then()
, который был удален - этот пример выполняется сприведенный ниже пример):
actions / blogActions.js
import * as types from '../types';
export const postsFetchData = () => dispatch => {
// dispatch(postsAreLoading(true)); // <== not needed
return axios
.get("http://localhost:3010/api/posts") // API url should be declared here
.then(({ data }) => { // es6 destructuring, data = response.data
/* if (response.status !== 200) {
throw Error(response.statusText);
} */ // <== not needed, the .catch should catch this
// dispatch(postsAreLoading(false)); // <== not needed
// dispatch(postsFetchDataSuccess(response.data)) // <== not needed, just return type and payload
dispatch({ type: types.LOAD_POSTS_SUCCESS, payload: data })
})
.catch(err => dispatch({ type: types.LOAD_POSTS_ERROR, payload: err.toString() }));
}
Как уже упоминалось в связанном вопросе, вам не нужен isLoading
с Reduxсвязанные контейнеры-компоненты.Поскольку реквизиты поступают из магазина redux
, React увидит изменение реквизита и соответствующим образом обновит подключенный компонент.Вместо этого вы можете использовать локальное состояние React ИЛИ просто проверить, присутствуют ли данные.
В приведенном ниже примере проверяется, присутствуют ли данные, в противном случае он загружается ...
BlogPage.js
import isEmpty from "lodash/isEmpty";
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import PostItem from "./PostItem";
import { postsFetchData } from "../../actions/blogActions";
class BlogPage extends PureComponent {
componentDidMount => () => this.props.postsFetchData(); // the API url should be placed in action creator, not here, especially if it's static
render = () => (
this.props.hasError // if this was an error...
? <p>Sorry! There was an error loading the items: {this.props.hasError}</p> // then an show error
: isEmpty(this.props.posts) // otherwise, use lodash's isEmpty to determine if the posts array exists AND has a length of 0, if it does...
? <p>Loading…</p> // then show loading...
: <div className="grid-style"> // otherwise, if there's no error, and there are posts in the posts array...
<PostItem posts={this.props.posts} /> // then show PostItem
</div>
)
}
export default connect(state => ({
// this is just inline mapStateToProps
posts: state.blog.posts
hasError: state.blog.hasError
}),
{ postsFetchData } // this is just an inline mapDispatchToProps
)(BlogPage);
redurs / index.js
import { combineReducers } from 'redux';
import * as types from '../types';
const initialState = {
posts: [], // posts is declared as an array and should stay that way
hasError: '' // hasError is declared as string and should stay that way
}
const blogPostsReducer = (state = initialState, { type, payload }) => {
switch (type) {
case types.LOAD_POSTS_SUCCESS:
return { ...state, posts: payload, hasError: '' }; // spread out any state, then update posts with response data and clear hasError
case types.LOAD_POSTS_ERROR:
return { ...state, hasError: payload }; // spread out any state, and update hasError with the response error
default:
return state;
}
}
export default combineReducers({
blog: blogPostReducer
// include any other reducers here
})
BlogPage.js (сisLoading
локальное состояние реакции)
import isEqual from "lodash/isEqual";
import isEmpty from "lodash/isEmpty";
import React, { Component } from "react";
import { connect } from "react-redux";
import PostItem from "./PostItem";
import { postsFetchData } from "../../actions/blogActions";
class BlogPage extends Component {
state = { isLoading: true };
componentDidUpdate = (prevProps) => { // triggers when props have been updated
const { posts } = this.props; // current posts
const prevPosts = prevProps.posts; // previous posts
const { hasError } = this.props; // current error
const prevError = prevProps.hasError // previous error
if (!isEqual(posts,prevPosts) || hasError !== prevError) { // if the current posts array is not equal to the previous posts array or current error is not equal to previous error...
this.setState({ isLoading: false }); // turn off loading
}
}
componentDidMount => () => this.props.postsFetchData(); // fetch data
render = () => (
this.state.isLoading // if isLoading is true...
? <p>Loading…</p> // then show loading...
: this.props.hasError // otherwise, if there was an error...
? <p>Sorry! There was an error loading the items: {this.props.hasError}</p> // then an show error
: <div className="grid-style"> // otherwise, if isLoading is false and there's no error, then show PostItem
<PostItem posts={this.props.posts} />
</div>
)
}
export default connect(state => ({
// this is just inline mapStateToProps
posts: state.blog.posts
hasError: state.blog.hasError
}),
{ postsFetchData } // this is just an inline mapDispatchToProps
)(BlogPage);