我有一個遠程API,它會生成一個通話記錄列表。這當然可能會很長,所以我需要延遲它。從RN文檔中我收集到最好的選擇是VirtualizedList。但文件非常缺乏。例如,它談到項目鍵。我可以爲它提供我自己的函數(使用日期/時間值),但getItem prop仍然要求索引從0開始的數組索引。那麼RN使用哪些鍵?另一件事是,我打印出對getItem和renderItem的調用,並且看到一個非常奇怪的模式(我已經將initialNumToRender和maxToRenderPerBatch設置爲13)。這一切都在應用程序啓動,沒有用戶交互。我的getItemCount返回15:如何用遠程數據實現VirtualizedList?
VirtualizedList.render() call
getItem 13 times: 0-12
getItem 0
renderItem 13 times: 0-12
VirtualizedList.render() call
getItem 13 times: 0-12
getItem 12
getItem 0
renderItem 12 times: 0-12
getItem 0
getItem 12
VirtualizedList.render() call
getItem 13 times: 0-12
getItem 12
getItem 0
renderItem 12 times: 0-12
getItem 0
getItem 12
getItem 0
getItem 12
(10 more like the 2 repeating above)
getItem 0-12
getItem 1
getItem 2
getItem 3
getItem 4
getItem 5
getItem 6
getItem 9
getItem 10
getItem 12 (Skipping some items here???)
onViewableItemsChanged, info= Object {viewableItems: Array(9), changed: Array(9)}
getItem 0-14
getItem 0-14
renderItem 0-14
onEndReached, info= Object {distanceFromEnd: 93.5} (what is that value 93.5????)
getItem 0-12
getItem 0-11
onViewableItemsChanged, info= Object {viewableItems: Array(12), changed: Array(5)}
getItem 0-14
onEndReached, info= Object {distanceFromEnd: 221???}
getItem 0-11
getItem 0-10
onViewableItemsChanged, info= Object {viewableItems: Array(11), changed: Array(1)}
getItem 0-14
請注意,我還沒有觸及屏幕。現在,當我向上滾動一下時,我得到以下事件:
getItem 0-12
(repeats for around 20 times)
onViewableItemsChanged, info= Object {viewableItems: Array(12), changed: Array(1)}
getItem 0-12
(repeats for around 20 times)
對於我滾動的每個像素,似乎都檢索到所有項目。
供參考,這是我的代碼:
import Expo from 'expo';
import React, { PureComponent } from 'react';
import { Platform, FlatList, VirtualizedList, View, StyleSheet, Text } from 'react-native';
import { combineReducers } from 'redux';
import { ListItem } from 'react-native-elements';
import { connect } from 'react-redux';
import I18n from '../i18n';
import { takeEvery, all, call, put, select } from 'redux-saga/effects';
import RecentRow from '../components/RecentRow';
import { getUserId } from './Settings';
import { AppText, AppHeaderText } from '../components/AppText';
// action types
const RECENT_LOAD = 'RECENT_LOAD';
const RECENT_LOAD_OK = 'RECENT_LOAD_OK';
const RECENT_LOAD_ERROR = 'RECENT_LOAD_ERROR';
// action functions
export function recentLoad(offset) {
return {
type: RECENT_LOAD,
offset: offset,
};
}
// reducers
function recent(state = { offset: 1, data: [] }, action) {
//console.log('recent', action);
switch (action.type) {
case RECENT_LOAD:
return {
...state,
offset: action.offset
};
case RECENT_LOAD_OK:
return {
...state,
data: action.data,
};
default:
return state;
}
}
// combined reducer
export const recentList = combineReducers({
recent: recent,
});
export const getRecent = state => state.recent;
export const getAccount = state => state.settings.account;
function* recentLoadData(action) {
const account = yield select(getAccount);
const URL = `https://www.xxxxx.xx/api/calls.php?userrname=${account.email}&offset=${action.offset}`;
try {
const response = yield call(fetch, URL);
if (response.status === 200) {
result = yield call([response, 'json']);
yield put({ type: RECENT_LOAD_OK, data: result });
} else {
yield put({ type: RECENT_LOAD_ERROR, error: response.status });
}
}
catch(error) {
console.log('error:', error);
yield put({ type: RECENT_LOAD_ERROR, error: error })
}
}
function* recentLoadSaga() {
yield takeEvery('RECENT_LOAD', recentLoadData);
}
export function* recentSaga() {
yield all([
recentLoadSaga(),
])
}
class RecentList extends PureComponent {
componentDidMount() {
this.props.loadRecentCalls();
}
_renderItem = (item, userid) => {
console.log('_renderItem', item);
//return <RecentRow row={item} userid={userid} />
return <ListItem title={item.item.name + ' ' + item.item.id } />
}
renderSeparator =() => {
return (
<View
style={{
height: 1,
width: "95%",
backgroundColor: "#CED0CE",
marginLeft: "5%"
}}
/>
);
};
render() {
console.log('RecentList.render()');
return (
<View style={styles.container}>
<View style={styles.lineitem}>
<View style={styles.header}>
<AppHeaderText>{I18n.t('calls')}</AppHeaderText>
</View>
</View>
<VirtualizedList
data={this.props.recent.data}
extraData={this.props}
keyExtractor={item => item.somekey}
renderItem={(item) => this._renderItem(item, this.props.userid)}
initialNumToRender="13"
maxToRenderPerBatch="13"
//ItemSeparatorComponent={this.renderSeparator}
ListEmptyComponent={() => {
return (
<View style={styles.centerScreen}>
<View>
<AppText>{I18n.t('nocallsfound')}</AppText>
</View>
</View>
)
}}
ListFooterComponent={() => {
return (
<Text>Footer goes here</Text>
)
}}
ListHeaderComponent={() => {
return (
<Text>Header goes here</Text>
)
}}
getItem={ (data, index) => {
console.log('getItem', index);
return {name: 'My Name', id: index, somekey: index+1000};
}}
getItemCount={ (data, index) => {
//console.log('getItemCount');
return 15;
}}
onEndReached={ (info) => {
console.log('onEndReached, info=', info);
}}
onViewableItemsChanged={ (info) => {
console.log('onViewableItemsChanged, info=', info);
}}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-start',
backgroundColor: 'whitesmoke',
},
header: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
borderColor: 'grey',
borderBottomWidth: 1,
height: 40,
},
lineitem: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor: 'white',
padding: 5,
},
centerScreen: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: 300,
}
});
const mapStateToProps = (state, props) => {
return {
recent: state.recentList.recent,
userid: getUserId(state),
};
};
const mapDispatchToProps = (dispatch, props) => {
return {
loadRecentCalls:() => dispatch(recentLoad(0)),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(RecentList);
所以我的主要問題是了,我怎麼把這個一起惰性加載數據?