Reputation: 41949
Reading this SO answer, I understand that when I pass a function to a react component, I have to bind a function in the constructor like this
constructor(props) {
super(props);
//binding function
this.renderRow = this.renderRow.bind(this);
this.callThisFunction = this.callThisFunction.bind(this);
}
or I'll get an error like this.
null is not an object: evaluating
this4.functionName
Following that advice, I bound the function in the constructor but I'm still getting the same error.
I'm making a Master/Detail app with React Native based on the Movies example in the react native repo, except that I don't use this syntax
var SearchScreen = React.createClass({
(which is what the repo is) but rather this ES6 style syntax
class ListOfLists extends Component {
In my list view, I render a row like this.
class MovieList extends Component{
constructor(props){
super(props);
this.selectMovie = this.selectMovie.bind(this);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
};
}
renderRow(
movie: Object,
sectionID: number | string,
rowID: number | string,
highlightRowFunc: (sectionID: ?number | string, rowID: ?number | string) => void,
) {
console.log(movie, "in render row", sectionID, rowID);
return (
<ListCell
onSelect={() => this.selectMovie(movie)}
onHighlight={() => highlightRowFunc(sectionID, rowID)}
onUnhighlight={() => highlightRowFunc(null, null)}
movie={movie}
/>
);
}
selectMovie(movie: Object) {
if (Platform.OS === 'ios') {
this.props.navigator.push({
title: movie.name,
component: TodoListScreen,
passProps: {movie},
});
} else {
dismissKeyboard();
this.props.navigator.push({
title: movie.title,
name: 'movie',
movie: movie,
});
}
}
render(){
var content = this.state.dataSource.getRowCount() === 0 ?
<NoMovies /> :
<ListView
ref="listview"
renderSeparator={this.renderSeparator}
dataSource={this.state.dataSource}
renderFooter={this.renderFooter}
renderRow={this.renderRow}
automaticallyAdjustContentInsets={false}
keyboardDismissMode="on-drag"
keyboardShouldPersistTaps={true}
showsVerticalScrollIndicator={false}
renderRow={this.renderRow}
}
The key line is this.selectMovie(movie)
. When I click a row with a movie name, I get an error
null is not an object:
evaluating this4.selectMovie
Question: why is it telling me null is not an object
or rather why is that function null?
Update:
I added the render method to the code to show where renderRow
is getting used
Upvotes: 8
Views: 21297
Reputation: 4528
Way to deal with this problem without modifying your code a lot is adding
this.renderRow = this.renderRow.bind(this)
to your class constructor.
class New extends Component{
constructor(){
this.renderRow = this.renderRow.bind(this)
}
render(){...}
}
you have add the property renderRow = { this.renderRow }
,In fact the renderRow executed with binded to null object.Try to console this
in renderRow
you will find it is GlobalObject
instead of Class MovieList
which you desire to.
Upvotes: 16
Reputation: 7106
Try using es6 syntax :
selectMovie = (movie) => {
if (Platform.OS === 'ios') {
this.props.navigator.push({
title: movie.name,
component: TodoListScreen,
passProps: {movie},
});
} else {
dismissKeyboard();
this.props.navigator.push({
title: movie.title,
name: 'movie',
movie: movie,
});
}
}
and then
constructor(props) {
super(props);
this.selectMovie = this.selectMovie();
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
})
};
}
and
renderRow = (...) => {
return (
<ListCell
onSelect={this.selectMovie(movie)}
onHighlight={() => highlightRowFunc(sectionID, rowID)}
onUnhighlight={() => highlightRowFunc(null, null)}
movie={movie}
/>
);
}
Upvotes: 1