I've had this issue pop up in one form or another over the years, and I finally figured out how to put it to words. Consider the following code:
import React, {Component} from "react";
import aFunction from "./Function";
export default class SomeComponent extends Component{
constructor(props){
super(props);
}
render(){
console.log(aFunction);
debugger;
return(
<div>some stuff</div>
)
}
}
The console.log() call will print information about aFunction, but if I type "aFunction" into the browser console I get a reference error. Why does this happen? Shouldn't console.log and the browser console via debugger have access to the same scope?
EDIT: I should clarify that I'm getting a reference error after allowing the "debugger" to occur before typing "aFunction". I'm not trying to call up block scoped variables after render() has completed.
It's an engine optimisation. Variables are invisible if they are not needed.
You can use a small hack to prevent it.
eval('debugger');
And when you use console.log you have it in your scope.
So, you can use another hack:
const temp = smthFromParentScope;
debugger;
It happens when you are in a nested function and there are no functions that have a reference to them.
function foo() {
const a = 1;
const b = 2;
function bar() {
console.log(a); // now we have a ref
}
function baz() {
debugger; // here we can see only 'a'
}
}
Related
I have a react component that has to pass a method to its children so that they can modify the state. So I created a function that allows to do that. I know I should bind the parent component to the this parameter of the function so that the children can successfully modify the state. The reason I want to do this is silly: I just don't know what to name the bound version ¯\_(ツ)_/¯. So what wanted to do is:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.modifyState = this.modifyState.bind(this);
}
modifyState() { /* blah blah*/ }
render() {
return(
<Child modifyState={this.modifyState} />
);
}
}
Now my question is:
Is there a reason why I really don't want to do this, can it cause any problems?
The reason I ask is, if there were no downsides, why not have this be the default behavior of it, in other languages this is always an instance of the class where the function (method) is defined. If you wanted the current behavior (this is the object who called the function from my understanding) just declare a global function.
I have started to learn ReactJS, I have a question about this case. const is used before declaration and it doesn't throw error. Why?
import React from "react";
export class item extends React.Component {
render() {
return <div style={customStyle}>test</div>;
}
}
const customStyle = { color: red };
export default item;
The reference to customStyle is inside a function, so it is resolved only when the function is called, which is after all the definitions have been processed.
Using means accessing. If you would construct a new item instance and call it's render method before the const customStyle line, then it would throw.
JS does not semantically enforce that a variable declared with let or const cannot be used before it's initialization, it is just a runtime error to do so.
The same behaviour can be seen if you access variables that don't exist at all:
function see() {
console.log(a); // not a semantical error, this is totally fine ...
}
// ...unless you try to execute it
see();
This question already has answers here:
Why and when do we need to bind functions and eventHandlers in React?
(2 answers)
Closed 3 years ago.
look at this code for example
import React, { Component } from ‘react’;
class App extends Component {
constructor(props) {
super(props);
this.clickFunction = this.clickFunction.bind(this);
}
clickFunction() {
console.log(this.props.value);
}
render() {
return(
<div onClick={this.clickFunction}>Click Me!</div>
);
}
}
what's the purpose of bind(this) ? it binds the function clickFunction to the context of the object which clickFunction is already bound to , let me illustrate what i am trying to say with a normal javascript code :
class my_class {
constructor() {
this.run = this.run.bind(this)
}
run() {
console.log(this.data)
}
}
my_class.data = 'this is data'
new my_class().run() //outputs 'undefined'
and if you remove bind(this) it will give you the same results
constructor() {
this.run = this.run
}
results :
new my_class().run() //still outputs 'undefined'
i am sure i am understanding something wrong and this might the worst question on earth however i am new to es6 and i am not used to classes yet so i apologize for that
Blame JavaScript not React. This is done to retain object instance when the function is going to be passed. Certainly, it must be semantically correct for the function to expect such object. Most common case is to bind this when passing object method. The keyword This depends on how the function is called not how/where it is created. The relationship to This should be maintained at invocation.
Consider:
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: . 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
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:
<button onClick={this.sayName.bind(this)}>Say My
Name</button>;
Or with ES6 syntax:
<button onClick={() => this.sayName()}>Say My
Name</button>;
And it should work!
In my React app, I have a handful of functions that I'd like to be able to access across a few similar components... however, I want to bind this to the shared functions so that they can do things like update the component state, etc... however, it seems that importing the functions and then trying to bind this in the 'typical' React manner does not work.
Here's an illustration of what I'd like to accomplish - in this case, clicking the rendered button would call the function from the imported shared function file and update the component state:
//shared_functions.js
const sharedFunctions = {
testFunction = () => {
this.setState({functionWasRun: true})
}
}
//MyComponent.jsx
import React, { Component } from 'react';
import sharedFunctions from '../static/scripts/shared_functions.js';
let { testFunction } = sharedFunctions;
class MyComponent extends Component {
constructor(props){
super(props);
this.testFunction = this.testFunction.bind(this)
this.state = {
functionWasRun: false
}
}
render(){
return(
<div>
<button onClick={this.testFunction}>Click</button>
</div>
)
}
}
Trying to run this code as is will return an error like:
Uncaught (in promise) TypeError: Cannot read property 'bind' of undefined
and I get what that's all about... but what I'd like to know is: is it possible to bind this to an imported function?
I'm starting to get a lot of similar-looking functions popping up throughout my app and I'd love to simplify things by abstracting them into a shared script, but I'm not sure how to achieve the typical this binding that's needed to achieve state-setting.
The following line is not trying to bind the imported testFunction but rather a method testFunction of <MyComponent>
To bind the imported function, refer to it directly, as follows:
this.testFunction = testFunction.bind(this);
// Notice how: ^--- there is no longer a this here
NB: You're example tries to use bind on an arrow function You cannot bind a new context to an arrow function. The this context of an arrow function will always be set to the location
were it is defined. You can get around this by declaring
testFunction using a regular function declaration:
const sharedFunctions = {
function testFunction(){
this.setState({functionWasRun: true})
}
}
I used it in the following way:
In constructor:
this.handleChange = handleChange.bind(this);
In the imported file (be careful, no arrow):
export const handleChange = function handleChange(event)
{
const { name, value } = event.target;
this.setState({
[name]: object
});
};
import ToastTimeout from 'toastTimout'
ToastTimeout.bind(this)('message to popup')
I was able to get the context of this in a simple service with a setTimeout function that changed the variable on this context
sorry for the sudo code
I'm using react-google-login in my react-redux project and having trouble accessing the props for the component in which this login button exists. I used react-facebook-login in a similar way and it works fine - however, console.log(this) in the loginGoogle() function prints 'undefined' whereas it printed the Javascript object representing the whole Login component in my similar loginFacebook() method. Any ideas as to how I can access this.props in loginGoogle()?
In my Login component:
//all needed import statements
class Login extends Component {
loginGoogle(response) {
console.log(response);
this.props.loginGoogleRequest(response.profileObj.email, response.accessToken, response.tokenObj.expires_in)
}
render() {
<GoogleLogin
clientId="{client id here}"
onSuccess={this.loginGoogle}
className="custom-google-btn"
/>
}
function mapDispatchToProps(dispatch) {
return {
loginGoogleRequest: (email, accessToken, expiresIn) => {
//some code that isn't being reached
}
}
}
export default connect(mapDispatchToProps)(Login);
I trimmed a lot of the fat out of this class in order to make it more readable - please let me know if it would help if I included more code in any way.
Try change loginGoogle definition to Arrow function:
loginGoogle(response) { => loginGoogle = (response) => {
An arrow function does not create its own "this", the this value of the enclosing execution context is used.
Or you may bind loginGoogle method, refer to this answer:
Why JSX props should not use arrow functions