【问题标题】:Render component after action dispatch动作分派后渲染组件
【发布时间】:2016-11-21 23:43:51
【问题描述】:

页面加载后,我在我的index.js 中调度了一个操作store.dispatch(getWeatherReports());,它会访问天气API。此操作通过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} />
  />

再次,相信我有适当的mapStateToPropsmapDispatchToProps 等。然后我希望在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 和万岁的方程式!数据就在那里……

所以我的问题是,感谢您对我的支持,我怎样才能得到它,以便我的哑组件等待尝试访问状态上的这些属性,直到在我最初调度的操作发生之后?

【问题讨论】:

    标签: javascript reactjs redux


    【解决方案1】:

    如果该 getWeatherReports 请求是由支持承诺而不是回调的东西发出的,以通知您成功的响应(即类似axios),那么您可以尝试使用像 redux-promise。

    redux-promise 会做的是拦截 dispatch 动作,并在 promise 没有被解决的情况下阻止它把动作转发给 store 的订阅者。

    一旦您收到成功的响应并解决了 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】:

      似乎store.dispatch(getWeatherReports()) 是一个异步 API 调用。因此,在 DOM 中渲染组件之前,您需要等待响应。

      解决方案:使用redux-connect

      要点:

      • 它允许你请求异步数据,将它们存储在 redux 状态和 将它们连接到您的反应组件。

      • 这个包由两部分组成:一部分允许你延迟 容器 渲染,直到发生一些异步操作。其他 将您的数据存储到 redux 状态并将您加载的数据连接到您的 容器

      在实现承诺之前,您的组件不会呈现。

      主要优点是:

      • 为 CSR(客户端渲染)和 SSR(服务器端渲染)配置简单而优雅。

      • 您可以在自己的 reducer 中对数据加载或加载成功等获取操作做出反应

      • 您可以创建自己的中间件来处理 Redux Async Connect 操作
      • 您可以在其他任何地方连接到加载的数据,只需使用简单的 redux @connect
      • 最后,您可以使用 Redux 开发工具调试和查看数据

      • 它还与React Router 集成,以防止在加载数据之前进行路由转换。

      确保不要忘记配置的 4 个步骤(described here):

      1. 连接你的数据,类似于 react-redux @connect
      2. 作为道具访问数据
      3. 连接 redux 异步减速器
      4. 使用 ReduxAsyncConnect 中间件渲染 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;
      

      使用多重承诺,

      @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);
        },
      }])
      

      【讨论】:

      • 有没有办法使用 react-redux 的 connect 方法来做到这一点?我不能是唯一一个处理这个问题的人,这让我认为我只是设置错误。我必须使用其他依赖项的事实是..
      【解决方案3】:

      在尝试访问.main 之前检查reports[0] 是否存在。如果是undefined,则显示加载微调器或其他东西...

       if (!reports[0]) return <div>Loading...</div>
      
       return (
         // your component like normal.
       )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-22
        • 2021-06-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-18
        相关资源
        最近更新 更多