2017-01-17 3 views
0

Я разрабатываю приложение с использованием React Native и redux. Экспресс js для запросов Ajax.React native/redux - setState не может обновляться во время существующего перехода состояния

Данные из моего запроса Ajax не загрузит и вот предупреждение я получаю:

Предупреждение: SetState (...): Не удается обновить в течение существующего состояния перехода (например, в пределах render или конструктор другого компонента ). Методы рендеринга должны быть чистой функцией реквизита и состояния ; побочные эффекты конструктора являются анти-образными, но могут быть перемещены в componentWillMount.

Не совсем уверен, что я делаю неправильно?

index.ios.js

import React, { Component } from 'react' 

import { 
    AppRegistry, 
    StyleSheet, 
    Text, 
    View, 
    NavigatorIOS 
} from 'react-native' 

import { Provider } from 'react-redux' 
import store from './src/store' 

import CategoryView from './src/category-view' 

class myApp extends Component { 
    render() { 
    return (
     <Provider store={store}> 
     <NavigatorIOS 
      initialRoute={{ 
      component: CategoryView, 
      title: 'myApp', 
      index: 0 
      }} 
     /> 
     </Provider> 
    ); 
    } 
} 

store.js

import { combineReducers, createStore, applyMiddleware } from 'redux' 
import thunkMiddleware from 'redux-thunk' 
import category from './reducers/category' 
import listings from './reducers/listings' 

const reducers = combineReducers({ 
    category, 
    listings 
}) 

const initialState = {} 

const store = createStore(
    reducers, 
    initialState, 
    applyMiddleware(
    thunkMiddleware 
) 
) 

export default store 

Вот мой вид файла:

import React from 'react' 
import { 
    View, 
    ListView, 
    ScrollView, 
    StyleSheet, 
    Image, 
    TouchableHighlight 
} from 'react-native' 

import { connect } from 'react-redux' 
import Listings from './listings' 
import BetView from './bet-view' 
import { getListings } from './actions/listings' 

const getDataSource = (listings) => 
    (new ListView.DataSource({ 
    rowHasChanged: (r1, r2) => r1 != r2 
    })).cloneWithRows(listings) 

const _ListingsView = ({dataSource, navigator, onPress, onLoad}) => { 
    onLoad() 
    return(
    <ScrollView> 
     <ListView 
     dataSource={dataSource} 
     renderRow={(row) => 
      <Listings 
      teamOne={row.game[0]} 
      teamTwo={row.game[1]} 
      date={row.date} 
      onPress={() => onPress(navigator, row.name)} 
      /> 
     } 
     /> 
    </ScrollView> 
) 
} 

const ListingsView = connect(
    (state) => { 
    return { 
     dataSource: getDataSource(state.listings.items || []), 
     loading: state.listings.loading 
    } 
    }, 
    (dispatch) => { 
    return { 
     onPress: (navigator, name) => 
     navigator.push({ 
      title: 'test', 
      component: BetView, 
      passProps: { 
      category: name 
      } 
     }), 
     onLoad:() => dispatch(getListings()) 
    } 
    } 
)(_ListingsView) 

export default ListingsView 

Действие Файл:

const URL = 'http://localhost:3000/listings' 

export const REQUEST_LISTINGS = 'request-listings' 
export const RECEIVE_LISTINGS = 'receive-listings' 

const requestListings =() => 
({ 
    type: REQUEST_LISTINGS 
}) 

const receiveListings = (items) => 
({ 
    type: RECEIVE_LISTINGS, 
    items: items || [] 
}) 

const shouldFetch = (state) => { 
    const res = (!state.listings.items || 0 == state.listings.items.length && !state.listings.loading) 
    return res 
} 

export const getListings =() => 
    (dispatch, getState) => 
    shouldFetch(getState()) 
    && dispatch(requestListings()) 
    && fetch(URL) 
     .then(res => res.json()) 
     .then(json => dispatch(receiveListings(json))) 

Вот редуктор:

import { RECEIVE_LISTINGS, REQUEST_LISTINGS } from '../actions/listings' 

export default (state = {}, action) => { 
    switch (action.type) { 
    case RECEIVE_LISTINGS: 
     return { 
     loading: false, 
     items: action.items 
     } 
    case REQUEST_LISTINGS: 
     return { 
     loading: true, 
     items: [] 
     } 
    } 
    return state 
} 
+0

Есть ли в вашем приложении какие-либо компоненты, которые используют локальное состояние? Другими словами, вы вызываете 'setState' где угодно? –

+0

Эта ошибка обычно возникает, когда вы пытаетесь обновить состояние в функции рендеринга. Реакция декларативна, поэтому рендер не должен манипулировать состоянием. –

+0

Возможно, вы используете компонент без состояния, и все происходит во время метода рендеринга. С базовым компонентом класса вы можете подключить getDataSource внутри componentWillMount –

ответ

0

вы могли бы попробовать что-то вроде этого. Я его не тестировал. Не уверен, что это прекрасно. но идея

import React, {Component} from 'react' 
import { 
    View, 
    ListView, 
    ScrollView, 
    StyleSheet, 
    Image, 
    TouchableHighlight 
} from 'react-native' 

import { connect } from 'react-redux' 
import Listings from './listings' 
import BetView from './bet-view' 
import { getListings } from './actions/listings' 

const getDataSource = (listings) => 
    (new ListView.DataSource({ 
    rowHasChanged: (r1, r2) => r1 != r2 
    })).cloneWithRows(listings) 

class _ListingsView extends Component { 


    componentWillMount() { 
    this.props.onLoad(); 
    } 

    render() { 
    return(
     <ScrollView> 
     <ListView 
      dataSource={this.props.dataSource} 
      renderRow={(row) => 
      <Listings 
       teamOne={row.game[0]} 
       teamTwo={row.game[1]} 
       date={row.date} 
       onPress={() => this.props.onPress(this.props.navigator, row.name)} 
      /> 
      } 
     /> 
     </ScrollView> 
    ) 
    } 
} 

const ListingsView = connect(
    (state) => { 
    return { 
     dataSource: getDataSource(state.listings.items || []), 
     loading: state.listings.loading 
    } 
    }, 
    (dispatch) => { 
    return { 
     onPress: (navigator, name) => 
     navigator.push({ 
      title: 'test', 
      component: BetView, 
      passProps: { 
      category: name 
      } 
     }), 
     onLoad:() => dispatch(getListings()) 
    } 
    } 
)(_ListingsView) 

export default ListingsView 

Таким образом, вы бы лучше, следуя их примеру: https://facebook.github.io/react-native/docs/listview.html

Или это, как я управлять ListViews в приложении я в настоящее время здание: https://github.com/kamiranoff/mythology/blob/master/src/components/HeroesList/HeroesList.js (В этом примере это немного отличается, потому что вызов api выполняется даже до того, как этот компонент визуализируется и фильтрует список, поэтому я обновляю состояние источника данных в компонентеWillReceiveProps)

+0

Большое спасибо. Я попробую и дам вам знать. – John

+0

Ваше решение устранило предупреждение setState, но данные по-прежнему не загружаются.Возможно, это связано с другой проблемой, на которую она жалуется: Возможное необработанное обещание (id: 0): React.Children.only ожидается получение одного дочернего элемента React. Invariant Violation: React.Children.only ожидается получение одного дочернего элемента React. – John

+0

Можете ли вы указать, из какого компонента эта ошибка возникает из полной stacktrace? Вы видите какой-либо компонент, который вы создали? –