React Native - binding a function to this

Viewed 2386

Im using react native 0.48 and I was wondering if the following is possible.

So my intention is to make my code a little bit more reusable. I have 4 classes each of them have similar code within componentDidMount. They share similar code componentDidMount() but the rest of the code in the render method is a little different.

My idea was this to share code across classes:

class 1

        componentDidMount(){
        componentDidMountTemplate().bind(this);
      }

where inside componentDidMountTemplate(which is a just an exported function), code that uses "this" keyword that should operate on objects in class 1, or basically any class that calls and binds this

however the line componentDidMountTemplate().bind(this); generates this error:

cannot call a class as a function

any solutions? ideas?

5 Answers

You are not binding anything, the bind method returns a new instance and you did not store it anywhere, and on top of that you did not run the bind on the function it self but instead you did it on the returned value of that function as you used the () and invoked it.
I'm not sure what exactly you are trying to reuse with your code as you didn't provide more details but basically you don't need to bind it at all and just pass the this object to the external function.

So you got 2 main options:

  • bind the external function and store it inside your class that needs to invoke it. and praying that anyone who will use your function will remember to bind it!!!.
    If by any chance your external function componentDidMountTemplate in your case is declared as an arrow function then binding won't work, because arrow functions use this in a lexical context (see my example).
  • Explicit pass the object as a parameter (which i find it the most readable and clear for consumers of this function util).

This is a snippet for just a small proof of concept:

class MyClass {
  externalFunc = ref => {
    console.log("passing the this explicit as a parameter", ref.state);
  };

  externalFunc2() {
    // depending on bind and praying for the best!
    console.log("depending on bind ", this.state);
  }

  externalFunc3 = () => {
    // with arrow functions bind won't work
    //because `this` is bound in a lexical context
    console.log("arrow function", this.state);
  };
}

const MyClassInstance = new MyClass();

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      someValue: "123"
    };
    this.externalFunc2 = MyClassInstance.externalFunc2.bind(this);
    this.externalFunc3 = MyClassInstance.externalFunc3.bind(this);
  }

  componentDidMount() {
    MyClassInstance.externalFunc(this);
    this.externalFunc2();
    this.externalFunc3();
  }

  render() {
    return (
      <div>
        <div>Look at the console!</div>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

You can use class properties and define componentDidMount as an arrow function (instead of method) inside of your components. Arrow functions use lexical this, so you don't have to bother with function binding. For example:

componentDidMount = () => {
  // you can access `this` safely
}

componentDidMountTemplate().bind(this);

should probably be

this.componentDidMountTemplate = componentDidMountTemplate.bind(this);

.bind() returns a new, bound function. You need to store that function in a value and then call it.

Now you can call this.componentDidMountTemplate()

Also anytime you write () next to a function, that function will be called

You can bind the function and then invoke it immediately like this:

componentDidMount() {
    (componentDidMountTemplate.bind(this))();
}

This consists of two parts -- first, binding the component context to the function (.bind(this)), and then second, invoking the returned function.

The error you are getting is suspicious. While you seem to be using bind incorrectly I would expect the error: Cannot read property 'bind' of undefined

Is your componentDidMountTemplate a class? I'm assuming you want to change that to a function and then follow the advice below regarding bind.


If you want to call the bound function you need the () after the bind(). Otherwise you are calling the unbound function and then trying to bind whatever is returned from it.

componentDidMount(){
    componentDidMountTemplate.bind(this)();
}

This means a new bound function is created, then called immediately

As many of the other answers are suggesting, it is common with React components to bind functions initially and store a reference to the bound function. However in your case you are likely only calling it once because the componentDidMount lifecycle method is only called once.

Related