网页加载后,我在index.js
内部发送了一个点击天气API的动作store.dispatch(getWeatherReports());
。此操作将通过redux
进程,并最终将返回的数据添加到名为weatherReports
的状态的属性中。此属性是一个空数组的对象。现在,我将粘贴代码的概述..并非所有这些都可以帮助您省去线路上的麻烦,因为从API输出数据不是我的问题。
这是我的index.js
:
import 'babel-polyfill';
import React from 'react';
import {render} from 'react-dom';
import configureStore from './store/configureStore';
import {Provider} from 'react-redux';
import {Router, browserHistory} from 'react-router';
import {StyleRoot} from 'radium';
import routes from './routes';
import {loadBlogs} from './actions/blogActions';
import {loadUsers, getActiveUser} from './actions/userActions';
import {getWeatherReports} from './actions/weatherActions';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import '../node_modules/toastr/build/toastr.min.css';
import './styles/app.scss';
const store = configureStore();
store.dispatch(loadBlogs());
store.dispatch(loadUsers());
store.dispatch(getActiveUser());
store.dispatch(getWeatherReports());
render(
<StyleRoot>
<Provider store={store}>
<Router history={browserHistory} routes={routes}/>
</Provider>
</StyleRoot>,
document.getElementById('app')
);
相信这会通过正确的流程来返回数据。然后我创建了一个smart
组件,它采用这种状态,并将其传递给一个哑组件。
class DashboardPage extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
weatherReports: []
};
}
<ContentBox
title="What The Wind Blew In"
content={<WeatherReport reports={this.props.weatherReports} />
/>
再次,相信我有适当的mapStateToProps
,mapDispatchToProps
等。然后我会在dumb
组件中显示数据。 WeatherReport.js
:
import React, {PropTypes} from 'react';
import styles from '../common/contentBoxStyles';
const WeatherReport = ({reports}) => {
console.log(reports);
return (
<div style={styles.body} className="row">
<div style={styles.weatherBoxContainer}>
<div className="col-sm-2 col-md-offset-1" style={styles.weatherBoxContainer.weatherCard}>
<div style={styles.weatherBoxContainer.weatherReport}>
<div style={styles.weatherBoxContainer.currentTemp}>
HERE IS MY PROBLEM!!
{reports[0].main.temp}
</div>
</div>
CA
</div>
<div className="col-sm-2" style={styles.weatherBoxContainer.weatherCard}>
<div style={styles.weatherBoxContainer.weatherReport}>
Report
</div>
UT
</div>
<div className="col-sm-2" style={styles.weatherBoxContainer.weatherCard}>
<div style={styles.weatherBoxContainer.weatherReport}>
Report
</div>
MN
</div>
<div className="col-sm-2" style={styles.weatherBoxContainer.weatherCard}>
<div style={styles.weatherBoxContainer.weatherReport}>
Report
</div>
DC
</div>
<div className="col-sm-2" style={styles.weatherBoxContainer.weatherCard}>
<div style={styles.weatherBoxContainer.weatherReport}>
Report
</div>
NY
</div>
</div>
</div>
);
};
WeatherReport.propTypes = {
reports: PropTypes.array
};
export default WeatherReport;
我的根本问题是在我的调度操作返回数据之前..我试图通过我的dumb
组件呈现它。因此,在尝试访问数据时收到以下错误:Uncaught TypeError: Cannot read property 'main' of undefined(…)
执行以下操作时:reports[0].main.temp
发生了什么事这是阻止我的应用程序向前移动,以便store.dispatch(getWeatherReports());
永远不会被调用。因此,如果我从等式中删除{reports[0].main.temp}
,则该过程继续并且动作将被分派。然后我可以用HMR和hooray来称呼这个等式!数据在那里......
所以我的问题,并且感谢与我的关系,我是如何得到它的,以便我的哑组件等待尝试在状态上访问这些属性,直到我的初始调度动作发生之后?
答案 0 :(得分:1)
在尝试访问reports[0]
之前,请检查.main
是否存在。如果是undefined
则显示加载微调器或其他东西......
if (!reports[0]) return <div>Loading...</div>
return (
// your component like normal.
)
答案 1 :(得分:1)
如果getWeatherReports请求是由支持promises的东西而不是回调来通知你成功的响应(例如axios),那么你可以尝试使用像 redux-这样的中间件许强>
redux-promise 将执行的操作是拦截调度操作,并阻止其将操作转发给商店的订户(如果承诺尚未解决)。
成功回复并且承诺得到解决后,中间件会创建一个与原始操作具有相同操作类型的新操作,但其负载包含您需要的数据。
您可以按照以下方式使用它:
import { createStore, applyMiddleware } from 'redux';
import promise from 'redux-promise';
const store = configureStore();
store.dispatch(loadBlogs());
...
...
store.dispatch(getWeatherReports());
const storeWithMiddleWare = applyMiddleware(promise)(store);
答案 2 :(得分:1)
似乎store.dispatch(getWeatherReports())
是异步API调用。因此,您需要在DOM中呈现组件之前等待响应。
解决方案:使用redux-connect。
关键点:
它允许您请求异步数据,将它们存储在redux状态和 将它们连接到您的反应组件。
此软件包由2部分组成:一部分允许您延迟 容器呈现,直到发生一些异步操作。另一个 将您的数据存储到redux状态,然后将加载的数据连接到您的数据 容器强>
在履行承诺之前,您的组件不会渲染。
主要优点是:
为CSR(客户端呈现)和SSR(服务器端呈现)配置简单而优雅。
您可以对您自己的Reducer中的数据加载或加载成功等提取操作做出反应
@connect
最后,您可以使用Redux Dev Tools
此外,它还与React Router集成,以防止在加载数据之前进行路由转换。
请确保您不要忘记4个配置步骤(described here):
Router
醇>
因此,DashboardPage
(假设 getWeatherReports()
将返回承诺),我们可以做的是:
如果你有使用装饰器的babel预设:
import { asyncConnect } from 'redux-connect';
@asyncConnect([{
key: 'lunch',
promise: ({ store: { dispatch }, params }) => dispatch(getWeatherReports())
}])
export default class DashboardPage extends React.Component {
...
}
否则:
class DashboardPage extends React.Component {
...
}
// sorry for the long name ;)
const asyncConnectedDashboardPage = asyncConnect([{
key: 'lunch',
promise: store.dispatch(getWeatherReports())
}])
export default asyncConnectedDashboardPage;
使用multipe promises,
@asyncConnect([{
promise: ({ store: { dispatch, getState } }) => {
const promises = [];
const state = getState();
if (/* some condition */) {
promises.push(dispatch(loadBlogs()))
}
if (/* some other condition */) {
promises.push(dispatch(loadUsers()))
}
promises.push(dispatch(getWeatherReports()))
return Promise.all(promises);
},
}])