J.Doe J.Doe - 9 days ago 4
React JSX Question

How to search data efficiently with React Native ListView

I am trying to implement a filter and search function that would allow user to type in keyword and return result(array) and re-render the row

This is the event arrays that being passed in into the createDataSource function

enter image description here

The problem I am having now is my search function can't perform filter and will return the entire parent object although I specifically return the indexed object.

Here's what I got so far

class Search extends Component {

state = { isRefreshing: false, searchText: '' }

componentWillMount() {
this.createDataSource(this.props);
}

componentWillReceiveProps(nextProps) {
this.createDataSource(nextProps);
if (nextProps) {
this.setState({ isRefreshing: false })
}
}

createDataSource({ events }) {
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
this.dataSource = ds.cloneWithRows(events);
}

//return arrays of event from events
renderRow(event) {
return <EventItem event={event} />;
}

onRefresh = () => {
this.setState({ isRefreshing: true });
this.props.pullEventData()
}

setSearchText(event) {
let searchText = event.nativeEvent.text;
this.setState({ searchText })

var eventLength = this.props.events.length
var events = this.props.events

const filteredEvents = this.props.events.filter(search)
console.log(filteredEvents);

function search() {
for (var i = 0; i < eventLength; i++) {
if (events[i].title === searchText) {
console.log(events[i].title)
return events[i];
}
}
}
}

render() {
const { skeleton, centerEverything, container, listViewContainer, makeItTop,
textContainer, titleContainer, descContainer, title, desc, listContainer } = styles;

return(
<View style={[container, centerEverything]}>
<TextInput
style={styles.searchBar}
value={this.state.searchText}
onChange={this.setSearchText.bind(this)}
placeholder="Search" />
<ListView
contentContainerStyle={styles.listViewContainer}
enableEmptySections
dataSource={this.dataSource}
renderRow={this.renderRow}
refreshControl={
<RefreshControl
refreshing={this.state.isRefreshing}
onRefresh={this.onRefresh}
title="Loading data..."
progressBackgroundColor="#ffff00"
/>
}
/>
</View>
)
}
}


enter image description here

As you can see from the image above, my code requires me to type in the full query text to display the result. And it displays all the seven array objects? why's that?

Answer

The syntax of Array.prototype.filter is wrong... it should take a callback that will be the item being evaluated for filtering.. if you return true it will keep it.

function search(event) {
  return ~event.title.indexOf(searchText)
}

You could even make the inline like..

const filteredEvents = this.props.events.filter(event => ~event.title.indexOf(searchText))

For understanding my use of ~, read The Great Mystery of the Tilde.

Since filter returns a new array, you should be able to clone your dataSource with it. If you didn't use filter, you would have to call events.slice() to return a new array. Otherwise, the ListView doesn't pickup the changes.