React native / redux - setState在现有状态转换期间无法更新

时间:2017-01-17 00:09:21

标签: javascript express react-native react-redux setstate

我正在使用React Native和redux开发一个应用程序。表达Ajax请求的js。

我的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
}

1 个答案:

答案 0 :(得分: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

或者这就是我在目前正在构建的应用程序中管理ListView的方法: https://github.com/kamiranoff/mythology/blob/master/src/components/HeroesList/HeroesList.js (在该示例中,它有点不同,因为甚至在此组件呈现之前和对列表进行过滤之前都会调用api,这就是我更新componentWillReceiveProps中数据源状态的原因)