有人可以帮我解决问题吗?
我正在尝试搜索本地 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"
}
]
最佳答案
这是一个非常好的开始。但是,您的代码存在一些问题。因此,让我们仔细检查一下,看看我们可以在哪些方面进行改进。
构造函数
首先,在构造函数中,您将数据设置为对象而不是数组。 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
返回一个对象,但您需要已放入搜索栏中的文本
。您需要将 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 上看到它的工作原理
关于React-native 搜索栏和 flatList 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54977824/