gpt4 book ai didi

javascript - React-redux 和 Redux-Thunk 中从 API 获取数据的问题

转载 作者:行者123 更新时间:2023-12-03 00:57:44 24 4
gpt4 key购买 nike

我正在努力理解react-redux和thunks库是如何工作的。

我想要实现的是在访问页面时使用一些API来获取所有帖子。

我正在 componentDidMount() 函数中调用 API。据我观察,我的代码被执行了 3 次,其中最后一个获得了帖子。

这是我的postReducer.js

import * as types from "../actions/actionTypes";
import initialState from "../reducers/initialState";

export function postsHaveError(state = false, action) {
switch (action.type) {
case types.LOAD_POSTS_ERROR:
return action.hasError;

default:
return state;
}
}

export function postsAreLoading(state = false, action) {
switch (action.type) {
case types.LOADING_POSTS:
return action.isLoading;

default:
return state;
}
}

export function posts(state = initialState.posts, action) {
switch (action.type) {
case types.LOAD_POSTS_SUCCESS:
return action.posts;

default:
return state;
}
}
// export default rootReducer;

postAction.js

import * as types from "./actionTypes";
import axios from "axios";

export function postsHaveError(bool) {
return {
type: types.LOAD_POSTS_ERROR,
hasError: bool
};
}

export function postsAreLoading(bool) {
return {
type: types.LOADING_POSTS,
isLoading: bool
};
}

export function postsFetchDataSuccess(posts) {
return {
type: types.LOAD_POSTS_SUCCESS,
posts
};
}

export function postsFetchData(url) {
return dispatch => {
dispatch(postsAreLoading(true));

axios
.get(url)
.then(response => {
if (response.status !== 200) {
throw Error(response.statusText);
}

dispatch(postsAreLoading(false));

return response;
})
.then(response => dispatch(postsFetchDataSuccess(response.data)))
.catch(() => dispatch(postsHaveError(true)));
};
}

以及我试图获取帖子的组件。

import React from "react";
import PostItem from "./PostItem";
import { connect } from "react-redux";
import { postsFetchData } from "../../actions/postActions";

class BlogPage extends React.Component {
constructor(props) {
super(props);

this.state = {
data: null
};
}

componentDidMount() {
this.props.fetchData("http://localhost:3010/api/posts");
}

render() {
if (this.props.hasError) {
return <p>Sorry! There was an error loading the items</p>;
}

if (this.props.isLoading) {
return <p>Loading…</p>;
}

console.log(this.props);
return (
<div>
<div className="grid-style">
<PostItem <<once i have posts they should go here>> />
</div>
</div>
);
}
}

const mapStateToProps = state => {
return {
posts: state.posts,
hasError: state.postsHaveError,
isLoading: state.postsAreLoading
};
};

const mapDispatchToProps = dispatch => {
return {
fetchData: url => dispatch(postsFetchData(url))
};
};

export default connect(
mapStateToProps,
mapDispatchToProps
)(BlogPage);

index.js

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import registerServiceWorker from "./registerServiceWorker";
import { BrowserRouter } from "react-router-dom";
import configureStore from "./store/configureStore";
import { Provider } from "react-redux";

const store = configureStore();

ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById("root")
);

registerServiceWorker();

app.js

import React, { Component } from "react";
import "./App.css";
import Header from "./components/common/header.js";
import Footer from "./components/common/footer.js";
import Main from "./components/common/main.js";
import "./layout.scss";

class App extends Component {
render() {
return (
<div className="App">
<Header />
<Main />
<Footer />
</div>
);
}
}

export default App;
BlogPage 所在的

main.js

import React from 'react';
import BlogPage from '../blog/BlogPage';
import AboutPage from '../about/AboutPage';
import { Route, Switch } from 'react-router-dom';
import LoginPage from '../authentication/LoginPage';

const Main = () => {
return (
<div>
<section id="one" className="wrapper style2">
<div className="inner">
<Switch>
<Route path="/about" component={AboutPage} />
<Route path="/login" component={LoginPage} />
<Route path="/" component={BlogPage} />
</Switch>
</div>
</section>
</div>
);
};

export default Main;

最佳答案

您的问题与此非常相似question (我还包括一个可以使用的代码沙箱)。请通读它并遵循工作示例,最重要的是,阅读 7 个提示(其中一些可能不适用于您的项目;但是,我强烈建议您安装 prop-types 来警告您,当您“偏离 1:1 还原状态)。

您面临的问题与此函数 postsFetchData 不返回 axios promise 有关(您还有一个不必要的 .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() }));
}

正如链接问题中提到的,您不需要使用 Redux 连接的容器组件的 isLoading 。由于 props 来自 redux 的存储,React 将看到 prop 的更改并相应地更新连接的组件。相反,您可以使用本地 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);

reducers/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 本地 React 状态)

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);

关于javascript - React-redux 和 Redux-Thunk 中从 API 获取数据的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52749548/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com