Are react's lifecycle method autobound? If not should we be binding them with .bind(this)?

后端 未结 1 794
南方客
南方客 2021-01-28 20:30

I think the title is pretty self-descriptive.

I\'ve building react components using the class notation, and I noticed that while handleSomething has to be m

1条回答
  •  清歌不尽
    2021-01-28 20:41

    Understanding of 'this' in JavaScript

    The 'this' keyword in a function is determined by the executing scope of the function. For example, the this in someFunction when calling with obj.someFunction() will be obj.

    A more concrete example:

    function handleClick() {
        console.log(this.state.value);
    }
    
    var state = { value: 1 }; // declare a var in window
    console.log("handleClick()");
    handleClick(); // Logged 1. The 'this' in the method will be window, because the method is called in window
    
    
    var obj = {
      state: { value: 2 },
      handleClick: function() {
        console.log(this.state.value);
      },
    };
    console.log("obj.handleClick();");
    obj.handleClick(); // Logged 2. The 'this' is referred to obj because the method is called in obj.
    
    // let's reassign the function to a temp var in window
    var temp = obj.handleClick;
    console.log("temp()");
    temp(); // Logged 1. The 'this' in the function is referred to window because the method is called in window.
    console.log("window.temp()");
    window.temp(); // this is equal to the one above.
    
    console.log("temp.bind(obj)");
    temp.bind(obj)(); // Logged 2. Bind the method and call the method, so the 'this' in the function is referred to obj.
    
    console.log("temp.bind(this)");
    temp.bind(this)(); // Logged 1. Since this in the executing scope is window. This effectively is the same calling in this.
    
    console.log("temp.bind(window)");
    temp.bind(window)(); // Logged 1. This is equal to the one above.
    

    Try it here: https://codepen.io/anon/pen/OvOpEa?editors=0012

    A blog post about this: https://hackernoon.com/understanding-javascript-the-this-keyword-4de325d77f68

    Back to your question

    If you look at render, componentWillMount, and handleSomething you defined in your class, it will become apparent why you need to bind your handler to this.

    render

    // Rerender
    ReactCurrentOwner.current = workInProgress;
    var nextChildren = void 0;
    {
      ReactDebugCurrentFiber.setCurrentPhase('render');
      nextChildren = instance.render();
      if (debugRenderPhaseSideEffects) {
        instance.render();
      }
      ReactDebugCurrentFiber.setCurrentPhase(null);
    }
    

    This is how react call redner(), where the instance is the object instance that has state, props, etc. You can try it very easily by putting a breakpoint in your render method and go back a call stack.

    handleSomething

    For example, if you define your class like this, with handleSomething as the onClick callback method of the button.

    class Button extends Component {
      handleSomething() {
        // 'this' will be undefined.
      }
    
      render() {
        return ();
      }
    }
    

    If you click the button, this is how react calls the onClick handler method.

      function callCallback() {
        fakeNode.removeEventListener(evtType, callCallback, false);
        // This is where react calls your method.
        func.apply(context, funcArgs);
        didError = false;
      }
    

    where func is handleSomething, and context is usually undefined in my debugging experience, and funcArgs is the arguments that being passed in the function.

    apply is similar to bind. The first argument is used to specify the this of the function, and the second argument is an array of parameters to pass into the function.

    See MDN for more information about apply: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

    In this case, the method handleSomething is being called with undefined as this; Therefore, if you didn't bind the method, your this will be undefined.

    I noticed that while handleSomething has to be manually bound to this, render and componentWillMount do not. Are method bound to this already?

    They are called with the instance of your class, so they already have this as your instance without using bind. I guess you can kind of say it's already bound to this.

    Is it ok to bind manually for notationally consistency's sake?

    You don't need to bind this with react's lifecycle methods. If you really want to, I guess you can bind those methods to this as well (there might be some side effects that I don't know, since I didn't really look that deeply into their source), but this is like doing obj.handleClick.bind(obj)(); instead of obj.handleClick();. It is unnecessary and will spend some clock cycles doing something that's not needed.

    0 讨论(0)
提交回复
热议问题