2016-12-08 2 views
0

Поэтому я могу переусердствовать с этой проблемой, но я не могу заставить свой компонент работать асинхронно.Redux Asynchronous Request Issue (Thunk Middleware)

По сути, я использую thunk для отправки действия, которое будет извлекать JSON с локального сервера и после его получения, передать его в редуктор и обновить состояние, а затем отобразить компонент.

Вместо этого компонент получает начальное состояние приложения как {} пустого объекта, тем самым выдавая ошибку, когда я использую map для визуализации компонента.

Вот что у меня есть:

index.js

import React from 'react'; 
import ReactDOM from 'react-dom'; 
import { Provider } from 'react-redux'; 
import { createStore, applyMiddleware } from 'redux'; 
import { Router, Route, IndexRoute, browserHistory } from 'react-router'; 
import thunk from 'redux-thunk'; 
import promise from 'redux-promise'; 

import App from './components/app'; 
import VotesContainer from './containers/votes-container'; 
import NewPoll from './containers/newpoll'; 
import VoteTemplate from './components/vote-template'; 
import Login from './components/auth/login'; 
import Signup from './components/auth/signup'; 
import reducers from './reducers/'; 

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; 

const store = createStore(reducers, composeEnhancers(applyMiddleware(thunk))) 

ReactDOM.render(
    <Provider store={store}> 
    <Router history={browserHistory}> 
     <Route path="/" component={App}> 
     <IndexRoute component={VoteTemplate} /> 
     <Route path="allposts" component={VotesContainer} /> 
     <Route path="login" component={Login} /> 
     <Route path="signup" component={Signup} /> 
     <Route path="newpoll" component={NewPoll} /> 
     </Route> 
    </Router> 
    </Provider> 
    , document.querySelector('#project')); 

действия/index.js

import axios from 'axios'; 
const ROOT_URL = 'http://localhost:1234'; 
import { browserHistory } from 'react-router'; 
import { FETCH_VOTES, CAST_VOTE } from './types'; 

export function fetchVotes(){ 
    return function(dispatch){ 
    axios.get(`${ROOT_URL}/newpost`) 
     .then(response => { 
     console.log('Dispatch!!') 
     dispatch({ 
      type: FETCH_VOTES, 
      payload: response.data 
     }) 
     }) 
    } 
} 

контейнер

import React, { Component } from 'react'; 
import { connect } from 'react-redux'; 
import * as actions from '../actions' 

class VotesContainer extends Component { 
    componentDidMount(){ 
    this.props.fetchVotes() 
    } 
    renderCards(){ 
    return(
     <div className="col s12 m6 l4"> 
     <div className="card blue-grey darken-1"> 
      <div className="card-content white-text"> 
      <span className="card-title">Vote App Title #1</span> 
      <p className="description">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p> 
      </div> 
      <div className="card-action"> 
      <a href="#">Results</a> 
      <a href="#">Date Created</a> 
      </div> 
     </div> 
     </div> 
    ) 
    } 
    render(){ 
    console.log(this.props.voteData) 
    return(
     <main className="votes-container container"> 
     <div className="row"> 
      {this.props.voteData.map(this.props.voteData.vote)} <<======= gives error since it is null first before dispatch 
     </div> 
     </main> 
    ) 
    } 
} 

function mapStateToProps(state){ 
    return {voteData: state.voteData}; 
} 

export default connect(mapStateToProps, actions)(VotesContainer) 
+0

Вы не можете использовать карту на объекте, вы пытаетесь использовать его для ключей объектов? – Kafo

+0

жаль, что это опечатка, это должно быть 'this.props.voteData.vote' – Alejandro

+1

Вы можете защитить от массива. Выполнение '(this.props.voteData.vote || []). Map (this.renderCards)' будет делать то, что вы хотите. Вы начнете с начального состояния, которое является пустым, а затем, когда вы отправляете его, будет заполнено, если вы не хотите начинать с другого исходного состояния с сервера? – Kafo

ответ

1

Вы должны установить начальное состояние магазина с тем, что вы ожидаете от компонента.
Если вы этого не делаете, вы не должны ожидать, что все данные будут там в начале render. Данные будут поступать только после извлечения, и до этого вы могли бы также добавить некоторые безопасные проверки в компонент.

+0

Ahh Я вижу. Я бы подумал, что, когда вызывается 'componentDidMount', и он асинхронно выбирает, он не будет отображать компонент до тех пор, пока данные не будут извлечены. Да, просто добавляя безопасные проверки, он отлично работает – Alejandro

+1

@Alejandro: Нет, пока он ждет данных, рендер будет вызываться, так как ожидание данных будет асинхронным процессом. После получения данных -> состояние обновляется -> рендер вызывается снова –

Смежные вопросы