React native / redux - setState 无法在现有状态转换期间更新
React native / redux - setState cannot update during an existing state transition
我正在使用 React Native 和 redux 开发应用程序。为 Ajax 请求表达 js。
我的 Ajax 请求中的数据无法加载,这是我收到的警告:
Warning: setState(...): Cannot update during an existing state
transition (such as within render
or another component's
constructor). Render methods should be a pure function of props and
state; constructor side-effects are an anti-pattern, but can be moved
to 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
}
你可以尝试这样的事情。我没有测试过。不确定它是否完美。但这就是想法
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 中更新数据源的状态)
我正在使用 React Native 和 redux 开发应用程序。为 Ajax 请求表达 js。
我的 Ajax 请求中的数据无法加载,这是我收到的警告:
Warning: setState(...): Cannot update during an existing state transition (such as within
render
or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved tocomponentWillMount
.
不完全确定我做错了什么?
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
}
你可以尝试这样的事情。我没有测试过。不确定它是否完美。但这就是想法
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 中更新数据源的状态)