有人可以帮我解决问题吗?
我正在尝试搜索本地JSON文件并返回相关数据。我的JSON文件包含餐厅名称和餐厅类型。
我不知道问题可能来自哪里。当我注释掉ListHeadComponent = {this.renderHeader}时,没有错误。但是,如果我将其注释掉,则不会显示任何内容。
我遇到的问题是:
Invariant Violation: Invariant Violation: Tried to get frame for out of range index NaN
This error is located at:
in VirtualizedList (at FlatList.js:662)
in FlatList (at SearchScreen.js:75)
in RCTView (at View.js:44)
in SearchScreen (created by SceneView)
in SceneView (at StackViewLayout.js:795)
in RCTView (at View.js:44)
in AnimatedComponent (at StackViewCard.js:69)
in RCTView (at View.js:44)
in AnimatedComponent (at screens.native.js:59)
in Screen (at StackViewCard.js:57)
in Card (at createPointerEventsContainer.js:27)
in Container (at StackViewLayout.js:860)
in RCTView (at View.js:44)
in ScreenContainer (at StackViewLayout.js:311)
in RCTView (at View.js:44)
in AnimatedComponent (at StackViewLayout.js:307)
in Handler (at StackViewLayout.js:300)
in StackViewLayout (at withOrientation.js:30)
in withOrientation (at StackView.js:79)
in RCTView (at View.js:44)
in Transitioner (at StackView.js:22)
in StackView (created by Navigator)
in Navigator (at createKeyboardAwareNavigator.js:12)
in KeyboardAwareNavigator (created by SceneView)
in SceneView (at createTabNavigator.js:39)
in RCTView (at View.js:44)
in RCTView (at View.js:44)
in ResourceSavingScene (at createBottomTabNavigator.js:113)
in RCTView (at View.js:44)
in ScreenContainer (at createBottomTabNavigator.js:103)
in RCTView (at View.js:44)
in TabNavigationView (at createTabNavigator.js:197)
in NavigationView (created by Navigator)
in Navigator (created by SceneView)
in SceneView (created by SwitchView)
in SwitchView (created by Navigator)
in Navigator (at createAppContainer.js:388)
in NavigationContainer (at App.js:24)
in RCTView (at View.js:44)
in App (at withExpoRoot.js:22)
in RootErrorBoundary (at withExpoRoot.js:21)
in ExpoRootComponent (at renderApplication.js:34)
in RCTView (at View.js:44)
in RCTView (at View.js:44)
in AppContainer (at renderApplication.js:33)
This error is located at:
in NavigationContainer (at App.js:24)
in RCTView (at View.js:44)
in App (at withExpoRoot.js:22)
in RootErrorBoundary (at withExpoRoot.js:21)
in ExpoRootComponent (at renderApplication.js:34)
in RCTView (at View.js:44)
in RCTView (at View.js:44)
in AppContainer (at renderApplication.js:33)
.js文件中的代码是:
import React from 'react';
import { ExpoConfigView } from '@expo/samples';
import { View, Text, FlatList, ActivityIndicator} from 'react-native';
import { SearchBar } from 'react-native-elements';
import restaurantList from '../assets/files/search.json';
export default class SearchScreen extends React.Component {
static navigationOptions = {
title: 'Search for Restaurants',
};
constructor() {
super();
this.state = {
loading: false,
data: {restaurantList},
error: null,
};
this.arrayholder = [];
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '86%',
backgroundColor: '#CED0CE',
marginLeft: '14%',
}}
/>
);
};
searchFilterFunction = text =>{
this.setState({
value: text,
});
const newData = this.arrayholder.filter(item => {
const itemData = `${item.name.toUpperCase()}
${item.type.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
})
this.setState({
data: newData,
});
};
renderHeader = () => {
return (
<SearchBar
placeholder="Type..."
value={this.state.value}
onChange={text => this.searchFilterFunction(text)}
/>
);
};
render() {
if (this.state.loading) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<ActivityIndicator />
</View>
);
}
return (
<View>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<Text>{item.name} {item.type}</Text>
)}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
/>
</View>
);
}
}
这是我的json文件
[
{
"name": "Shake Shack",
"type":"american"
},
{
"name": "BonChon Chicken",
"type": "korean"
},
{
"name": "Starbucks",
"type:": "cafe"
}
]
答案 0 :(得分:0)
这是一个非常好的开始。但是,您的代码有几个问题。因此,让我们看一下它,看看可以在哪里进行一些改进。
首先,在构造函数中,您要使数据成为对象而不是数组。 FlatList不能与它们与数组一起使用的对象一起使用,因此这将立即引起您的问题。您确实需要从{}
周围删除restaurantList
。
constructor() {
super();
this.state = {
loading: false,
data: {restaurantList}, // You shouldn't have {} around the restaurantList
error: null,
};
this.arrayholder = []; // we also don't need this
}
您应该将构造函数更新为此
constructor (props) {
super(props);
this.state = {
loading: false,
data: restaurantList, // notice we have no {} around restaurantList
error: null,
value: ''
};
}
在renderHeader
函数中,您使用的是onChange
而不是onChangeText
。 onChange
返回一个对象,但是您希望将text
放入搜索栏中。您需要像这样更新renderHeader
函数。
renderHeader = () => {
return (
<SearchBar
placeholder="Type..."
value={this.state.value}
onChangeText={text => this.searchFilterFunction(text)} // now we are using the correct function to capture the text
/>
);
};
此功能存在多个问题。首先,您正在查看this.arrayholder
,它是空的。实际上,我们不需要额外的数组来保存数据,因为我们可以使用之前导入的restaurantList
。其次,您在字符串上使用indexOf
,最好使用includes
。
searchFilterFunction = text => {
this.setState({
value: text
});
const newData = restaurantList.filter(item => {
const itemData = `${item.name.toUpperCase()} ${item.type.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.includes(textData); // this will return true if our itemData contains the textData
});
this.setState({
data: newData
});
};
在FlatList中,您应该使用extraData
属性,因为这将允许FlatList在基础数据更改时更新。您还应该添加一个keyExtractor
。
<FlatList
keyExtractor={(item, index) => `${index}`}
extraData={this.state} // <- add this prop
data={this.state.data}
renderItem={({ item }) => (
<Text>{item.name} {item.type}</Text>
)}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
/>
因此,如果我们将所有这些放在一起,则添加一个数据模拟,以便我们可以检查其是否有效。我们应该得到这样的东西。
// mock the data as you didn't provide an example
const restaurantList = [
{
type: 'Italian',
name: 'DiMaggio'
},
{
type: 'Greek',
name: 'Athena'
}
];
export default class SearchScreen extends React.Component {
static navigationOptions = {
title: 'Search for Restaurants'
};
constructor (props) {
super(props);
this.state = {
loading: false,
data: restaurantList,
error: null,
value: ''
};
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '86%',
backgroundColor: '#CED0CE',
marginLeft: '14%'
}}
/>
);
};
searchFilterFunction = text => {
this.setState({
value: text
});
const newData = restaurantList.filter(item => {
const itemData = `${item.name.toUpperCase()} ${item.type.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.includes(textData);
});
this.setState({
data: newData
});
};
renderHeader = () => {
return (
<SearchBar
placeholder="Type..."
value={this.state.value}
onChangeText={text => this.searchFilterFunction(text)}
/>
);
};
render () {
if (this.state.loading) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<ActivityIndicator />
</View>
);
} else {
return (
<View style={styles.container}>
<FlatList
keyExtractor={(item, index) => `${index}`}
extraData={this.state}
data={this.state.data}
renderItem={({ item }) => (
<Text>{item.name} {item.type}</Text>
)}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
/>
</View>
);
}
}
}
您可以在以下小吃https://snack.expo.io/@andypandy/flatlist-with-search
上看到它的工作原理