Last active
          January 14, 2024 16:02 
        
      - 
      
- 
        Save fongandrew/f28245920a41788e084d77877e65f22f to your computer and use it in GitHub Desktop. 
Revisions
- 
        fongandrew revised this gist Jul 1, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -69,7 +69,7 @@ have a `favoriteWord` property, so calling the function results in an exception. Before a Javascript expert shouts at me, note that in Javascript-land, we generally think of the relationship between `dog` and `bark` not as "parent" and "child", but that `dog` is the "context" for `bark`. `dog.bark` means "Call the bark function with the context of dog". And `this` always refers to the context in a given function. 
- 
        fongandrew revised this gist May 24, 2017 . 1 changed file with 10 additions and 3 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -69,9 +69,9 @@ have a `favoriteWord` property, so calling the function results in an exception. Before a Javascript expert shouts at me, note that in Javascript-land, we generally think of the relationship between `dog` and `bark` not as "parent" and "child", but that `dog` is "context" for `bark`. `dog.bark` means "Call the bark function with the context of dog". And `this` always refers to the context in a given function. To understand why someone (if not necessarily you or me) might think this is cool, consider the following: @@ -90,6 +90,13 @@ original `dog` object. So we can freely assign `bark` to `cat.meow`. And when we call `cat.meow`, the caller is `cat`, so `this.favoriteWord` refers to "Meow!" instead of "Woof!". As an aside, the "context" for a Javascript function or class method is distinct from ["context" in React](https://facebook.github.io/react/docs/context.html). As the React developers themselves indicate, if you're just getting started with React, ignore React's version of context. However, you do need to understand context in the Javascript sense insofar that you're using classes to represent React components and invoking stuff like `this.props` or `this.setState({ ... })`. Bind ---- 
- 
        fongandrew revised this gist May 13, 2017 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -186,18 +186,18 @@ points to our function, just fine and dandy. But what React is doing behind the scenes is assigning `this.sayName` to another variable. That is, it's just like this: ```javascript let onClick = this.sayName; onClick(); // Technically a click event is passed to onClick // but this doesn't matter for our purposes ``` And just like our dog example, we get an error. Because `this` is undefined. This is extra confusing because in previous versions of React, React would "autobind" the event handler for you, so it would work. But at some point, Facebook decided to stop doing that, so ... here we are. So how can we fix our component? We just do binding ourselves, like this: ```jsx <button onClick={this.sayName.bind(this)}>Say My Name</button>; 
- 
        fongandrew revised this gist May 13, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -58,7 +58,7 @@ The `bark` variable is distinct from `dog.bark`. To make this a little clearer, let's just use a different name. ```javascript let bark2 = dog.bark; bark2(); ``` 
- 
        fongandrew revised this gist May 13, 2017 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,7 +3,7 @@ Start With This Before getting to React, it's helpful to know what `this` does generally in Javascript. Take the following snippet of code. It's written in ES6 but the principles for `this` predate ES6. ```javascript class Dog { @@ -58,7 +58,7 @@ The `bark` variable is distinct from `dog.bark`. To make this a little clearer, let's just use a different name. ```javascript let = dog.bark; bark2(); ``` 
- 
        fongandrew revised this gist May 13, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -51,7 +51,7 @@ bark() # => Woof! It's tempting to say `this` and `self` do the same things. They both refer to the parent of a function in this case. But in the case of Python, `self` is determined at the time the function is defined. In the case of Javascript, `this` is determined at the time the function is called. The `bark` variable is distinct from `dog.bark`. 
- 
        fongandrew revised this gist May 13, 2017 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,5 @@ Start With This --------------- Before getting to React, it's helpful to know what `this` does generally in Javascript. Take the following snippet of code. It's written in ES6 but the principles for `this` 
- 
        fongandrew created this gist May 13, 2017 .There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,237 @@ This ---- Before getting to React, it's helpful to know what `this` does generally in Javascript. Take the following snippet of code. It's written in ES6 but the principles for `this` have been around for a while. ```javascript class Dog { constructor() { this.favoriteWord = "Woof!"; } bark() { return this.favoriteWord; } } let dog = new Dog(); dog.bark(); // => Woof! ``` Cool. That makes sense. But remember, functions are also objects in their own right in Javascript, so let's try this: ```javascript let bark = dog.bark; bark(); // => Error ``` Ruh roh. What happened? You probably got a message saying `favoriteWord` wasn't a property of `undefined`, or something similar. But `this.favoriteWord` clearly refers to the `Dog` instance, so what gives? The answer is that `this` is determined at the time the function is called, not the time the function is defined. This can be super confusing if you're coming from, say, Python, where the following code works: ```python class Dog: def __init__(self): self.favorite_word = "Woof!" def bark(self): return self.favorite_word; dog = Dog() bark = dog.bark bark() # => Woof! ``` It's tempting to say `this` and `self` do the same things. They both refer to the parent of a function in this case. But in the case of Python, `self` is determined at the time the funciton is defined. In the case of Javascript, `this` is determined at the time the function is called. The `bark` variable is distinct from `dog.bark`. To make this a little clearer, let's just use a different name. ```javascript let bark = dog.bark; bark2(); ``` We're creating a new variable (`bark2`). `bark2` doesn't have a parent at the time it's called, unlike `dog.bark` (which has `dog` as a parent). `bark2` is a top level variable, so it's "parent" is `undefined`. `undefined` doesn't have a `favoriteWord` property, so calling the function results in an exception. Before a Javascript expert shouts at me, note that in Javascript-land, we generally think of the relationship between `dog` and `bark` not as "parent" and "child", but as "caller" and "callee". `dog.bark` means "Hey dog, call your 'bark' function!". And `this` always refers to the caller in the callee function. To understand why someone (if not necessarily you or me) might think this is cool, consider the following: ```javascript let cat = { favoriteWord: "Meow!" }; cat.meow = bark; cat.meow(); // => "Meow!" bark(); // Nope, still broken ``` This works because the `this` variable in the `bark` function isn't tied to the original `dog` object. So we can freely assign `bark` to `cat.meow`. And when we call `cat.meow`, the caller is `cat`, so `this.favoriteWord` refers to "Meow!" instead of "Woof!". Bind ---- OK, let's add a new wrinkle. Consider this now: ```javascript let alwaysWoof = bark.bind(dog); alwaysWoof(); // => "Woof!" ``` Why does this work? It's because calling `bind` on a function returns a copy of that function in which `this` is always set to whatever arg you pass to `bind`. This applies even if we change the caller of the bound function: ```javascript cat.meow = alwaysWoof; cat.meow(); // => "Woof!" ``` In the class context, it's pretty common to bind to `this`: ```javascript class ConsistentDog { constructor() { this.favoriteWord = "Woof!"; let bark = function() { return this.favoriteWord; } this.bark = bark.bind(this); } } let conDog = new ConsistentDog(); let conBark = conDog.bark; conBark(); // => "Woof!" ``` Writing `.bind(this)` over and over is pretty annoying, so in ES6, you can also avoid writing `.bind(this)` with the `() => ...` syntax: ```javascript class SimpleDog { constructor() { this.favoriteWord = "Woof!"; this.bark = () => this.favoriteWord; /* Or you can do this if you need more than one statement for your function. this.bark = () => { let simpleWord = this.simpleWord; return simpleWord; }; */ } } let simDog = new SimpleDog(); let simBark = simDog.bark; simBark(); // => "Woof!" ``` Now with React Classes ----------------------- Still with us? OK, now to bring in React. Consider this React component, defined as an ES6 class: ```jsx class Welcome extends React.Component { render() { return <button onClick={this.sayName}>Say My Name</button>; } sayName() { alert(this.props.name); } } ``` In React, you invoke like this: `<Welcome name="Bob" />`. This renders a button. Clicking the button should trigger an alert with "Bob". Except it doesn't. Because in the above example, `this` would be undefined in the `sayName` function. What's happening inside the render function is that `this` refers to the current instance of our React component. That component has a `sayName` function defined, so `this.sayName` points to our function, just fine and dandy. But what React is doing behind the scenes is assigning `this.sayName` to another variable. That is, it's just like this: ``` let onClick = this.sayName; onClick(); // Technically a click event is passed to onClick // but this doesn't matter for our purposes ``` And just like our dog example, we can an error. Because `this` is undefined. This is extra confusing because in previous versions of React, React would "autobind" the event handler for you, so it would work. But at some point, Facebook decided to stop doing that, so ... here we are. So how we fix our component? We just do the "autobind" ourselves, like this: ```jsx <button onClick={this.sayName.bind(this)}>Say My Name</button>; ``` Or with ES6 syntax: ```jsx <button onClick={() => this.sayName()}>Say My Name</button>; ``` And it should work! One final note -- when we bind a function in React, we can do that not only when the render function is called, but before as well. So take this: ```jsx class Welcome extends React.Component { constructor(props) { super(props); this.boundSayName = this.sayName.bind(this); } render() { return <button onClick={this.boundSayName}>Say My Name</button>; } sayName() { alert(this.props.name); } } ``` We can do `this.boundSayName` instead of `this.boundSayName.bind(this)`. Because `this.boundSayName` was already bound to `this` in the constructor. And that's it! Hope it helps!