【问题标题】:React native / redux - setState cannot update during an existing state transitionReact native / redux - setState 在现有状态转换期间无法更新
【发布时间】:2017-05-31 22:06:08
【问题描述】:

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

我的 Ajax 请求中的数据不会加载,这是我收到的警告:

警告:setState(...):在现有状态期间无法更新 过渡(例如在render 或其他组件的 构造函数)。渲染方法应该是 props 的纯函数和 状态;构造函数副作用是一种反模式,但可以移动 到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
}

【问题讨论】:

  • 您的应用中是否有使用本地状态的组件?换句话说,你在哪里打电话给setState
  • 当您尝试更新渲染函数中的状态时,通常会发生此错误。 React 是声明性的,因此渲染不应该操纵状态。
  • 可能是因为您使用的是无状态组件,并且一切都发生在渲染方法期间。使用类基础组件,您可以将 getDataSource 连接到 componentWillMount
  • 您在_ListingsViewrender() 方法中调用onLoad()。使用 componentWillMount 等组件生命周期方法避免这种情况
  • 我刚刚更新了我的问题并添加了显示渲染方法的 index.ios.js

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


【解决方案1】:

你可以试试这样的。我还没有测试过。不确定它是否完美。但这就是想法

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 的调用甚至在这个组件被渲染和过滤列表之前就已经进行了,这就是为什么我在 componentWillReceiveProps 中更新数据源的状态)

【讨论】:

  • 非常感谢。我会试一试,然后告诉你。
  • 您的解决方案确实修复了 setState 警告,但数据仍未加载。可能与它抱怨的另一个问题有关:可能未处理的承诺拒绝(id:0):React.Children.only 预计会收到一个 React 元素子项。不变违规:React.Children.only 预计会收到一个 React 元素子元素。
  • 你能指出错误来自完整堆栈跟踪中的哪个组件吗?你看到你创建的任何组件了吗?
  • 一个反应组件必须返回一个节点(例如:
  • 是错误的来源。它必须只有一个孩子。非常感谢您的帮助。
猜你喜欢
  • 2017-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-20
  • 2017-05-16
  • 2016-09-20
  • 2017-09-04
相关资源
最近更新 更多