React / Redux无法迭代状态

时间:2016-08-16 20:10:34

标签: javascript reactjs redux

我正在学习React / Redux,在将我的单页网页应用转换为框架/范例时,我遇到了一个问题。我试图做的是让Web应用程序的初始状态具有一个数组,该数组将由API请求中的对象填充,此数组被称为" make"。我想这样做,所以我可以显示"制作"从加载时网站首页的API开始。这可以在以下index.js文件中看到:

import App from './App';
import './index.css';
import configureStore from './redux/store'
import { Provider } from 'react-redux'

let makesUrl = 'the url to the API'
let cached = cache.get(makesUrl)
let makes = []

// Future cache setup.
if(!cached) {
    console.log("NOT CACHED")
}
else {
    console.log("CACHED")
}

// Get the makes via API.
fetch(makesUrl).then((response) => {
    // Pass JSON to the next 'then'
    return response.json()
}).then((json) => {
    json.makes.forEach((make) => {
        makes.push(make)
    })
})

let initialState = {
  grids: [],
  makes: makes
}

let store = configureStore(initialState)

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

statedispatch映射到道具,并传递到App.js文件中需要它们的组件:

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import './App.css'
import Head from './components/Head'
import Middle from './components/Middle'
import Foot from './components/Foot'
import actions from './redux/actions'

class App extends Component {

  render() {
    return (
      <div className="App">
        <div>
          <Head />
          <div className="middle container">
            <Middle actions={this.props.actions} makes={this.props.makes}/>
          </div>
          <Foot />
        </div>
      </div>
    );
  }
}

function mapStateToProps(state) {
  return state
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(actions, dispatch)
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

在所有方面,在chrome dev工具中,我可以看到API调用成功并且状态显示为makes: Array[62]内部有62个对象,但是如果我在控制台中记录数组的长度将这些组成的组件传递给如下所示,它表示长度为0,并且数组的每个索引都是未定义的。

import React, { Component } from 'react'

    class MakeButtons extends Component {

        handleClick(event) {
            event.preventDefault()
            console.log("CLICK")
        }

        render() {
            return(
                <div>
                    {
                        console.log(this.props.makes.length)
                    }
                </div>
            )
        }
    }

    export default MakeButtons

这基本上是我过去几个小时试图弄清楚的,所以我可以使用forEachmap函数返回每个对象的链接/按钮虽然开发工具显示状态正常,但在目前这不起作用。任何帮助/解释将不胜感激!

1 个答案:

答案 0 :(得分:1)

所以你真的需要为你的init设置一个动作/缩减器,然后你可以在componentWillMountcomponentDidMount中调用它,因为它们只在加载你的应用时被调用一次。

就像你现在这样做的方式,你有一个fetch和一个应用程序使用来自 not 的提取数据,等待异步调用在启动应用程序之前完成。

您只想创建初始化操作,因此您的操作创建者将是:

   import * as services from './services';

   function initMyAppDispatcher(type, data, status) {
       return {
          type, 
          data,
          status
        };
   }


   export function initMyApp(dispatch, makesUrl) {
      dispatch(initMyAppDispatcher(actions.INIT_APP, {}, 'PENDING');

      return services.myInitCall(makesUrl)
         .then((data) =>
             dispatch(initMyAppDispatcher(actions.INIT_APP, data, 'SUCCESS'),
            (error) =>
             dispatch(initMyAppDispatcher(actions.INIT_APP, error, 'FAILURE'),
         )
         .catch(yourErrorHandling);
   }

然后,您希望实现Services.myInitCall,只需确保将其作为承诺导出。在您的情况下,只要您可以访问该行,就可以将该行替换为fetch(makesUrl)。然后让它像这样设置,你可以像这样设置你的减速器:

   case actions.INIT_APP:
            if (action.status) {
                switch (action.status) {
                    case PENDING:
                        //you can use this to create a "loading" state like a spinner or whatever
                        return state;
                    case SUCCESS:
                        // note: this is immutablejs syntax, use whatever you prefer
                        return state.set('makes', action.data);
                   case FAILURE:
                        return state;

                    default:
                        return state;
                }
            }
            return state;

需要注意的一点是,我已在我的动作创建者中发送,因为我使用mapDispatchToProps代替mapToProps。所以你的容器看起来像这样:

import * as actionCreators from './action-creators';

function mapStateToProps(state) {

    return {
        makes: state.get('makes')
    };
}

function mapDispatchToProps(dispatch, ownProps) {
    return {
        initMyApp: actionCreators.initMyApp.bind(null, dispatch)
    };
}


export default function(component = Component) {
    return connect(mapStateToProps, mapDispatchToProps)(component);
}

然后在您的组件componentWillMountcomponentDidMount中,传入并调用您的init函数

   componentDidMount() {
       this.props.initMyApp();

   }