首先,我的代码 正在工作(所有内容都正确导出等),但它并没有等待异步返回数据。 我正在使用 redux-thunk 作为我的异步中间件
我有一个名为 async.js
的动作export function itemsHasErrored(bool) {
return {
type: 'ITEMS_HAS_ERRORED',
hasErrored: bool
};
}
export function itemsIsLoading(bool) {
return {
type: 'ITEMS_IS_LOADING',
isLoading: bool
};
}
export function itemsFetchDataSuccess(items) {
return {
type: 'ITEMS_FETCH_DATA_SUCCESS',
items
};
}
export function itemsFetchData(url) {
return (dispatch) => {
dispatch(itemsIsLoading(true));
fetch(url)
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
dispatch(itemsIsLoading(false));
return response;
})
.then((response) => response.json())
.then((items) => dispatch(itemsFetchDataSuccess(items)))
.catch(() => dispatch(itemsHasErrored(true)));
};
}
我的减速机
export function itemsHasErrored(state = false, action) {
switch (action.type) {
case 'ITEMS_HAS_ERRORED':
return action.hasErrored;
default:
return state;
}
}
export function itemsIsLoading(state = false, action) {
switch (action.type) {
case 'ITEMS_IS_LOADING':
return action.isLoading;
default:
return state;
}
}
export function items(state = [], action) {
switch (action.type) {
case 'ITEMS_FETCH_DATA_SUCCESS':
return action.items;
default:
return state;
}
}
我有一个容器组件 asyncContainer.js
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux'
import {itemsFetchData} from '../../../actions/async';
import AsyncUI from './asyncUI'
class AsyncContainer extends Component {
componentDidMount() {
this.props.fetchData('http://5826ed963900d612000138bd.mockapi.io/items');
}
render() {
if (this.props.hasErrored) {
return <p>Sorry! There was an error loading the items</p>;
}
if (this.props.isLoading) {
return <p>Loading…</p>;
}
//This fails to wait
return (
<AsyncUI />
);
}
}
AsyncContainer.propTypes = {
fetchData: PropTypes.func.isRequired,
items: PropTypes.array.isRequired,
hasErrored: PropTypes.bool.isRequired,
isLoading: PropTypes.bool.isRequired
};
const mapStateToProps = (state) => {
return {
items: state.items,
hasErrored: state.itemsHasErrored,
isLoading: state.itemsIsLoading
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: (url) => dispatch(itemsFetchData(url))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(AsyncContainer);
最后我有一个名为 asyncUI.js 的简单UI组件以函数方式编写
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux'
const AsyncUI = (items) => {
return (
<ul>
{items.map((item) => (
<li key={item.id}>
{item.label}
</li>
))}
</ul>
);
}
const mapStateToProps = (state) => {
return {
items: state.items
};
};
export default connect(mapStateToProps)(AsyncUI);
在 asyncContainer.js 中,您可以看到对我的简单UI组件的调用
return (
<AsyncUI />
);
但是在调用 asyncUI.js 中的redux store items 的属性为空数组时,items.map
失败
但是,如果我从 asyncUI.js 中删除代码并将其放在 asyncContainer.js 中,则可以使用
这是 asyncContainer.js中的代码
class AsyncContainer extends Component {
componentDidMount() {
this.props.fetchData('http://5826ed963900d612000138bd.mockapi.io/items');
}
render() {
if (this.props.hasErrored) {
return <p>Sorry! There was an error loading the items</p>;
}
if (this.props.isLoading) {
return <p>Loading…</p>;
}
//THIS IS WHERE I HAD <Async />
return (
<ul>
{this.props.items.map((item) => (
<li key={item.id}>
{item.label}
</li>
))}
</ul>
);
}
}
AsyncContainer.propTypes = {
fetchData: PropTypes.func.isRequired,
items: PropTypes.array.isRequired,
hasErrored: PropTypes.bool.isRequired,
isLoading: PropTypes.bool.isRequired
};
const mapStateToProps = (state) => {
return {
items: state.items,
hasErrored: state.itemsHasErrored,
isLoading: state.itemsIsLoading
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: (url) => dispatch(itemsFetchData(url))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(AsyncContainer);
我认为问题是组件 在项目数据准备好之前呈现。这是正常的反应行为。那么我如何“推迟”渲染。正如您所看到的,我正在尝试使用容器/组件样式的体系结构。我总是可以使用上面提到的解决方案,但我想坚持使用这个容器/组件。 我是否需要深入研究Promises等? 我不应该使用asyncUI.js的功能写作方式吗? 我有点困惑。
答案 0 :(得分:2)
尝试:
const AsyncUI = ({items}) => {
/* ^ see ^ */
return (
<ul>
{items.map((item) => (
<li key={item.id}>
{item.label}
</li>
))}
</ul>
); }
这会从你在items
函数中反应的道具中取出mapStateToProps
值,这是一个对象,而不是数组(因此没有map
函数)。
注意:这应该可以解决您的问题,但它仍然技术上尝试在2个实例中准备好之前呈现这些项目:
组件首次渲染。 itemsIsLoading
的初始状态为false
,因此第一次渲染将失败所有安全检查。 items
的默认值为[]
,因此在调度<ul></ul>
操作之前,它应该只显示itemsIsLoading(true)
一小段时间。您可以将初始状态设置为true
以停止此操作,或将加载检查更改为
if (this.props.isLoading || this.props.items.length != 0) {
return <p>Loading…</p>;
}
可以对这些解决方案的实际必要性进行论证。
在fetch
返回订单后,调度操作将导致另一个简短的呈现<ul></ul>
,因为在设置项目之前加载状态设置为false
。有关解决此问题的一种方法,请参阅dgrijuela's answer。另一种方法是不分派单独的操作,并使ITEMS_FETCH_DATA_SUCCESS
和ITEMS_HAS_ERRORED
操作也将itemsIsLoading
值更改为false(多个reducer可以对同一操作类型起作用)。
答案 1 :(得分:0)
您在dispatch(itemsIsLoading(false))
dispatch(itemsFetchDataSuccess(items))
试试这样:
// async.js
...
export function itemsFetchData(url) {
return (dispatch) => {
dispatch(itemsIsLoading(true));
fetch(url)
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
})
.then((response) => response.json())
.then((items) => {
dispatch(itemsFetchDataSuccess(items));
dispatch(itemsIsLoading(false));
})
.catch(() => dispatch(itemsHasErrored(true)));
};
}
答案 2 :(得分:0)
请参阅Michael Peyper一个好的答案
事实证明,问题在于我的 asyncUI 组件的编码功能样式。我把它转换回了标准&#39;有状态的组件和它有效的宾果。
asyncContainer.js
class AsyncContainer extends Component {
componentDidMount() {
this.props.fetchData('http://5826ed963900d612000138bd.mockapi.io/items');
}
render() {
if (this.props.hasErrored) {
return <p>Sorry! There was an error loading the items</p>;
}
if (this.props.isLoading) {
return <p>Loading…</p>;
}
return (
<AsyncUI />
)
}
}
asyncUI.js
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux'
class AsyncUI extends Component {
render() {
return (
<ul>
{this.props.items.map((item) => (
<li key={item.id}>
{item.label}
</li>
))}
</ul>
)
}
}
const mapStateToProps = (state) => {
return {
items: state.items,
};
};
export default connect(mapStateToProps)(AsyncUI);
希望这可以帮助任何人: - )