如何解决 React redux 中的数据加载问题
How to solve data loading issue in React redux
我想弄清楚如何在数据仍在加载时 manage/display 这个组件。
我在这个案例中使用了 React redux。
有什么解决这个问题的建议吗?
虽然我用延迟加载包装了它,但在这种情况下似乎并没有那么有效。
对此有何建议。
//Actions.js
export const getContact= () => dispatch => {
dispatch(setResumesLoading());
axios
.get('/api/contacts')
.then(res =>
dispatch({
type: GET_CONTACTS,
payload: res.data
})
).catch (err => dispatch (returnErrors(err.response.data, err.response.status)));
};
//component.js
import React, {Component} from 'react';
import {Grid, Cell, List, ListItem, ListItemContent, Button} from 'react-mdl';
import { connect } from 'react-redux';
import { getContact, deleteContact} from '../../actions/resumeActions';
import PropTypes from 'prop-types';
class Contact extends Component{
static propTypes = {
getContact: PropTypes.func.isRequired,
deleteContact: PropTypes.func.isRequired,
resume: PropTypes.object.isRequired,
isAuthenticated: PropTypes.bool,
auth: PropTypes.object.isRequired
}
componentDidMount() {
this.props.getContact();
}
onDeleteContactClick = (id) => {
this.props.deleteContact(id);
};
render(){
const { contacts } = this.props.resume;
const { user } = this.props.auth;
return(
<div>
{/* {loading ? <Loading /> : <ResultsComponent results={data} />} */}
{contacts.map(({ _id, contact_name, contact_phone, contact_email, contact_skype, contact_image }) => (
<Grid key={_id} timeout={100} classNames="fade">
{ this.props.isAuthenticated && (user.is_admin === true) ?
<Button className="remove-btn"
color="danger"
size="sm"
onClick= {this.onDeleteContactClick.bind(this, _id)}>
×
</Button> : null }
<Cell col={6}>
<div style={{textAlign: 'center'}}>
<h2> {contact_name} </h2>
<img src={contact_image}
alt="avatar"
style={{height: '40%', borderRadius: '50%', width: '50%'}}
img-rounded />
</div>
</Cell>
<Cell col={6} className="contact-right-col text-center">
<h2 >Contact Me</h2>
<hr className="resume-left-contact-section-border" />
<List>
<ListItem>
<ListItemContent className="contact-list-item">
<i className="fa fa-phone-square" aria-hidden="true"/>
{contact_phone}
</ListItemContent>
</ListItem>
</List>
</Cell>
</Grid>
))}
</div>
)
}
}
const mapStateToProps = (state) => ({
resume: state.resume,
isAuthenticated : state.auth.isAuthenticated,
auth: state.auth
});
export default connect(mapStateToProps, {getContact, deleteContact }) (Contact);
处理组件呈现的一种常见方法,尤其是当它是容器时,是实现加载 activity 指示器,一旦您有要显示的数据,该指示器就会消失。只需确保在您的本地状态中实现 loading
布尔值,一旦您确认数据存在,将 loading
更改为 false
。
async componentWillMount() {
await getWorkexperience();
this.setState({
loading: false,
});
}
...
render() {
const { data, loading } = this.state;
return (
<div>
{/*
Check the status of the 'loading' variable. If true, then display
the loading spinner. Otherwise, display the data.
*/}
{loading ? <LoadingSpinner /> : <ResultsComponent results={data} />}
</div>
);
}
这是您要找的东西吗?
在现成的解决方案中,有一些包可以立即使用:
好吧,您可以在现有的操作列表中再添加两个操作。一个用于获取 API 调用开始的状态,一个用于任何错误。有点像这样:
import * as types from "./actionTypes";
export function beginApiCall() {
return { type: types.BEGIN_API_CALL };
}
export function apiCallError() {
return { type: types.API_CALL_ERROR };
}
然后您可以通过在正确的时间调度它们来利用这些操作。
export const getWorkexperience = () => dispatch => {
dispatch(beginApiCall());
axios
.get('/api/workexperiences')
.then(res =>
dispatch({
type: GET_WORKEXPERIENCE,
payload: res.data
})
).catch (err => dispatch(apiCallError(error)););
};
然后你必须为这个动作创建一个新的reducer。为此编写一个 reducer 有点棘手。您需要存储正在进行的 API 个调用的数量,并根据它们的状态递增或递减它们。为此,您可以将 _SUCCESS
附加到所有动作创建器和缩减器中的现有动作类型。
import * as types from "../actions/actionTypes";
import initialState from "./initialState";
function actionTypeEndsInSuccess(type) {
return type.substring(type.length - 8) === "_SUCCESS";
}
export default function apiCallStatusReducer(
state = initialState.apiCallsInProgress,
action
) {
if (action.type == types.BEGIN_API_CALL) {
return state + 1;
} else if (
action.type === types.API_CALL_ERROR ||
actionTypeEndsInSuccess(action.type)
) {
return state - 1;
}
return state;
}
//initialState.js
export default {
state1: [],
state2: [],
apiCallsInProgress: 0
};
进入组件后,在发出获取请求后,您可以使用此 reducer 的状态来呈现微调器或任何您想要的东西,只需从 reducer 中获取它即可。
const loading = useSelector((state) => state.apiCallsInProgress > 0);
或者您可以像这样通过 mapStateToProps
访问它,我看到您已经使用它来获取组件中的道具。
const mapStateToProps = (state) => ({
resume: state.resume,
isAuthenticated : state.auth.isAuthenticated,
auth: state.auth,
loading: state.apiCallsInProgress > 0
});
你可以return这样的函数内容。
{loading ? (
Loading...
) : (
<div>My component</div>
)}
我想弄清楚如何在数据仍在加载时 manage/display 这个组件。
我在这个案例中使用了 React redux。
有什么解决这个问题的建议吗?
虽然我用延迟加载包装了它,但在这种情况下似乎并没有那么有效。
对此有何建议。
//Actions.js
export const getContact= () => dispatch => {
dispatch(setResumesLoading());
axios
.get('/api/contacts')
.then(res =>
dispatch({
type: GET_CONTACTS,
payload: res.data
})
).catch (err => dispatch (returnErrors(err.response.data, err.response.status)));
};
//component.js
import React, {Component} from 'react';
import {Grid, Cell, List, ListItem, ListItemContent, Button} from 'react-mdl';
import { connect } from 'react-redux';
import { getContact, deleteContact} from '../../actions/resumeActions';
import PropTypes from 'prop-types';
class Contact extends Component{
static propTypes = {
getContact: PropTypes.func.isRequired,
deleteContact: PropTypes.func.isRequired,
resume: PropTypes.object.isRequired,
isAuthenticated: PropTypes.bool,
auth: PropTypes.object.isRequired
}
componentDidMount() {
this.props.getContact();
}
onDeleteContactClick = (id) => {
this.props.deleteContact(id);
};
render(){
const { contacts } = this.props.resume;
const { user } = this.props.auth;
return(
<div>
{/* {loading ? <Loading /> : <ResultsComponent results={data} />} */}
{contacts.map(({ _id, contact_name, contact_phone, contact_email, contact_skype, contact_image }) => (
<Grid key={_id} timeout={100} classNames="fade">
{ this.props.isAuthenticated && (user.is_admin === true) ?
<Button className="remove-btn"
color="danger"
size="sm"
onClick= {this.onDeleteContactClick.bind(this, _id)}>
×
</Button> : null }
<Cell col={6}>
<div style={{textAlign: 'center'}}>
<h2> {contact_name} </h2>
<img src={contact_image}
alt="avatar"
style={{height: '40%', borderRadius: '50%', width: '50%'}}
img-rounded />
</div>
</Cell>
<Cell col={6} className="contact-right-col text-center">
<h2 >Contact Me</h2>
<hr className="resume-left-contact-section-border" />
<List>
<ListItem>
<ListItemContent className="contact-list-item">
<i className="fa fa-phone-square" aria-hidden="true"/>
{contact_phone}
</ListItemContent>
</ListItem>
</List>
</Cell>
</Grid>
))}
</div>
)
}
}
const mapStateToProps = (state) => ({
resume: state.resume,
isAuthenticated : state.auth.isAuthenticated,
auth: state.auth
});
export default connect(mapStateToProps, {getContact, deleteContact }) (Contact);
处理组件呈现的一种常见方法,尤其是当它是容器时,是实现加载 activity 指示器,一旦您有要显示的数据,该指示器就会消失。只需确保在您的本地状态中实现 loading
布尔值,一旦您确认数据存在,将 loading
更改为 false
。
async componentWillMount() {
await getWorkexperience();
this.setState({
loading: false,
});
}
...
render() {
const { data, loading } = this.state;
return (
<div>
{/*
Check the status of the 'loading' variable. If true, then display
the loading spinner. Otherwise, display the data.
*/}
{loading ? <LoadingSpinner /> : <ResultsComponent results={data} />}
</div>
);
}
这是您要找的东西吗?
在现成的解决方案中,有一些包可以立即使用:
好吧,您可以在现有的操作列表中再添加两个操作。一个用于获取 API 调用开始的状态,一个用于任何错误。有点像这样:
import * as types from "./actionTypes";
export function beginApiCall() {
return { type: types.BEGIN_API_CALL };
}
export function apiCallError() {
return { type: types.API_CALL_ERROR };
}
然后您可以通过在正确的时间调度它们来利用这些操作。
export const getWorkexperience = () => dispatch => {
dispatch(beginApiCall());
axios
.get('/api/workexperiences')
.then(res =>
dispatch({
type: GET_WORKEXPERIENCE,
payload: res.data
})
).catch (err => dispatch(apiCallError(error)););
};
然后你必须为这个动作创建一个新的reducer。为此编写一个 reducer 有点棘手。您需要存储正在进行的 API 个调用的数量,并根据它们的状态递增或递减它们。为此,您可以将 _SUCCESS
附加到所有动作创建器和缩减器中的现有动作类型。
import * as types from "../actions/actionTypes";
import initialState from "./initialState";
function actionTypeEndsInSuccess(type) {
return type.substring(type.length - 8) === "_SUCCESS";
}
export default function apiCallStatusReducer(
state = initialState.apiCallsInProgress,
action
) {
if (action.type == types.BEGIN_API_CALL) {
return state + 1;
} else if (
action.type === types.API_CALL_ERROR ||
actionTypeEndsInSuccess(action.type)
) {
return state - 1;
}
return state;
}
//initialState.js
export default {
state1: [],
state2: [],
apiCallsInProgress: 0
};
进入组件后,在发出获取请求后,您可以使用此 reducer 的状态来呈现微调器或任何您想要的东西,只需从 reducer 中获取它即可。
const loading = useSelector((state) => state.apiCallsInProgress > 0);
或者您可以像这样通过 mapStateToProps
访问它,我看到您已经使用它来获取组件中的道具。
const mapStateToProps = (state) => ({
resume: state.resume,
isAuthenticated : state.auth.isAuthenticated,
auth: state.auth,
loading: state.apiCallsInProgress > 0
});
你可以return这样的函数内容。
{loading ? (
Loading...
) : (
<div>My component</div>
)}