1

I've rewrite a component from createClass to class definition to fit eslint-react-native linting, then I found I cannot bind function to element in Array as it used to. The former code looks like this:

createClass({
  render() {
    return (
      <ListView style={styles.listView}
        dataSource={this.state.data}
        renderRow={this._renderTopic}
      />
    )
  },
  _renderTopic(topic) {
    return (
      <TouchableHighlight onDelayColor="#dddddd"
        onPress={() => this._jumpTo(topic.id) }
      >
    )
  },
  _jumpTo(id) {
    this.props.navigator.push({
      name: 'Topic page',
      component: Topic,
      passProps: {
       topicId: id,
      },
    });
  }
})

When I change it to class definition:

{
  render() {
    return (
      <ListView style={styles.listView}
        dataSource={this.state.data}
        renderRow={this._renderTopic}
      />
    )
  }
  _renderTopic(topic) {
    return (
      <TouchableHighlight onDelayColor="#dddddd"
        onPress={() => this._jumpTo(topic.id) }
      >
    )
  }
  _jumpTo(id) {
    this.props.navigator.push({
      name: 'Topic page',
      component: Topic,
      passProps: {
       topicId: id,
      },
    });
  }
}

It does not work again. And give an error while press the Touchable: this2._jumpTo is not a function

So I changed it again:

{
  render() {
    return (
      <ListView style={styles.listView}
        dataSource={this.state.data}
        renderRow={this._renderTopic}
      />
    )
  }
  _renderTopic(topic) {
    const nav = this.props.navigator
    let jumpTo = function(id) {
      nav.push({
        name: 'Topic page',
        component: Topic,
        passProps: {
         topicId: topic.id,
        },
      });
    };
    return (
      <TouchableHighlight onDelayColor="#dddddd"
        onPress={jumpTo}
      >
    )
  }
}

This would through error immediately: possible unhandled promise rejection cannot read property _currentElement of null. (Which is strange here, the jumpTo function should be lazy, right?)

So what's the right way to bind an dynamic function to item in ListView?

2
  • Are you willing to use ES6? It would make this question trivial Commented Apr 6, 2016 at 3:10
  • @MatthewHerbst Yes, I'm writing ES6, using Babel-eslint and eslint to lint my code. Source code is here: github.com/kxxoling/PythonChina.app Linted code is not commited yet. Commented Apr 6, 2016 at 3:14

4 Answers 4

4

I think whitep4nther was heading in the right direction, I do the following to get around the binding in the render method

```

{
  constructor(props) {
    super(props);
      this._renderTopic = this._renderTopic.bind(this);
  }
}

```

Check out this link from the docs https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding

Sign up to request clarification or add additional context in comments.

3 Comments

I have several renderXX and fetchXX methods here, so I have to bind them multi times. Any good ideas to fix this?
You should look at using something like lodash, It has a _.bindAll function lodash.com/docs#bindAll
This helps! Thank you!
2

With second example, wild guess ?

renderRow={this._renderTopic.bind(this)}

7 Comments

Not tested, but using bind is not suggested based on eslint-react plugin. github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/… Even this works, I'd rather a better solution.
He's talking about your problem right after : github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/…. He suggests binding the method in the constructor, which is essentially the same without the need to create a new function in each render.
But to be fair, you don't need this kind of optimizations till some point
And there is no need to have a "better" solution, this method was specifically created to solve theses kind of problem
The answer is in the link you posted earlier, at the bottom in the page ! ;) "Unfortunately React ES6 classes do not autobind their methods like components created with the older React.createClass"
|
0

You need to bind this to the method

<ListView
   dataSource={this.state.dataSource}
   renderRow={this._renderTopic.bind(this)}
/>

and add the _renderTopic method in constructor :

constructor(props) {
  super(props);
  this._renderTopic = this._renderTopic.bind(this);
}

Comments

0

You don't have to bind this if you use the react class constructor and then use arrow functions.

This is possible because arrow functions don't create a closure like functions do.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      content: "Some content"
    };
  }
  clickHandler = event => {
    //handle the click
  };
  render() {
    return (
      <div>
        <p> Some Content </p>
        <button onClick={this.clickHandler}> Click Me</button>
      </div>
    );
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.