I'm trying to acces a class property via 'this' in a callback function of an onClick event, but there is a scope-issue and the property isn't defined.
I've tried a couple of setups, but I think I'm just hitting myself in my confusion more than anything.
class MyClass extends React.Component {
constructor(props) {
super(props)
this.myProperty = "myValue"
}
onElementClicked = (event, other, parameters) => {
console.log(this.myProperty) //Undefined.
}
render() {
return (
<div>
<SubElement click={this.onElementClicked} />
</div>
)
}
}
function SubElement({ click }) {
const number = "Click me", other = null, parameters = null;
return (
<p>
<span onClick={e => click(e, other, parameters)}>
{number}
</span>
</p>
);
}
ReactDOM.render(
<MyClass />,
document.querySelector("main")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<main>Please enable JS</main>
You should not be using class fields and arrow functions for methods as they are attached to the object instance instead of the class prototype, which defeats prototypal inheritance.
Replace the arrow function with a regular function with the method definition syntax. Also, bind the function to this before passing it as prop, otherwise it will be "detached" from the class:
export default class MyClass {
constructor() {
this.myProperty = "myValue"
this.onElementClicked = this.onElementClicked.bind(this);
}
onElementClicked(event, other, parameters) {
console.log(this.myProperty) // Works.
}
render() {
ReactDOM.render(
<div>
<subElement click={this.onElementClicked}/>
</div>
)}
}
}
Related
when i try to use variable in my class function getting this error
Cannot read property 'zoomInIndex' of undefined
it is working fine if i have one function, can some one help me out how to use the variable in inner function or how to bind the inner function context?
class MyContainer extends Component {
constructor(props) {
super(props);
this.testClick = this.testClick.bind(this);
this.zoomClick = this.zoomClick.bind(this);
this.testVarible= "this is a test";
}
zoomClick(inout) {
return function(e) {
console.log(this.testVarible); // this is not working
}
}
testClick(){
console.log(this.testVarible);
}
}
if i use fat arrow functions it is working fine
zoomClick = inout => e => {
console.log(this.testVarible);
}
but i don't want to use fat arrow functions in react components since i ran into a lot of issues with my webpack configuration.
so my question is how to use the variable in inner function or how to bind the inner function context with out fat arrow syntax?
You need to bind the function returning from the zoomClick():
zoomClick(inout) {
return function(e) {
console.log(this.testVarible); // this is not working
}.bind(this); // <-- bind(this)
}
The anonymous function which was returned had no context of this and thus it was giving the error. Because zoomClick is already bound in the constructor, you just need to bind the function(e) { ... }
You can bind it to the class context one of two ways:
returnFunction = returnFunction.bind(this); or function() {}.bind(this).
class MyContainer extends React.Component {
constructor(props) {
super(props);
this.testClick = this.testClick.bind(this);
this.zoomClick = this.zoomClick.bind(this);
this.testVarible = "this is a test";
}
zoomClick(inout) {
let returnFunction = function(e) {
console.log(this.testVarible);
return this.testVarible;
};
returnFunction = returnFunction.bind(this);
return returnFunction;
}
testClick(){
console.log(this.testVarible);
}
render() {
return (
<div>{this.zoomClick(false)(false)}</div>
);
}
}
ReactDOM.render(
<MyContainer/>,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
i don't want to use fat arrow functions in react components since i ran into a lot of issues with my webpack configuration
I'm guessing you tried to use class fields with the Babel plugin and that caused you some grief.
It's OK to use the traditional method of binding in the constructor and use arrow functions elsewhere in the code without running into those problems.
class MyContainer extends React.Component {
constructor(props) {
super(props);
this.zoomClick = this.zoomClick.bind(this);
this.testVarible = "this is a test";
}
zoomClick() {
return (e) => {
console.log(this.testVarible);
}
}
render() {
return <Button handleClick={this.zoomClick} />
}
}
function Button({ handleClick }) {
return <button onClick={handleClick()}>Click</button>
}
ReactDOM.render(
<MyContainer /> ,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container"></div>
I'm currently creating a component in react and i'm using the ES Lint rule react/jsx-no-bind. My issue here is that I want to be able to pass a parameter to my components function. Here is the code I would like to use to be able to do so:
class LanguageDropdown extends Component {
constructor(props) {
super(props);
this.state = {};
}
changeLanguage = (lang) => {
console.log(lang)
};
render() {
return (
<div>
{this.props.languages.map(lang => <button onCLick={() => this.changeLanguage(lang)}>{lang}</button>)}
</div>
)
}
...
This pulls up the ESlint error:
JSX props should not use arrow functions
I'm not entirely sure how to achieve this without using an arrow function or using .bind(). I could add a data-attribute to the button element and then just pass in the event into the changeLanguage function and fetch the attribute using event.target() but this doesn't feel like it's the way it should be approached in React.
Can someone tell me what would be the correct way?
You can refactor button into its own component:
class MyButton extends Component {
static propTypes = {
language: PropTypes.string.isRequired,
};
onClick = () => console.log(this.props.language);
render() {
const {language} = this.props;
return (
<button onClick={this.onClick} type="submit">
{language}
</button>);
}
}
and then in your LanguageDropDown class, use MyButton like this:
class LanguageDropdown extends Component {
...
render() {
return (
<div>
{this.props.languages.map(lang => <MyButton key={lang} language={lang}/>)}
</div>
)
}
...
}
A couple of additional things:
You have a typo onCLick should be onClick
You need a key for repeated items
try the below code.
here I tried by taking the value into the state, same can be tried using props.
class LanguageDropdown extends Component {
constructor(props) {
super(props);
this.state = {languages:['telugu','hindi','english']};
// this.changeLanguage = this.changeLanguage.bind(this);
}
changeLanguage(event,lang){
//event.preventDefault();
console.log('change lang: '+JSON.stringify(lang));
};
render() {
return (
<div>
{this.state.languages.map(lang => <button onClick={(event)=>this.changeLanguage(event,lang)}>{lang}</button>)}
</div>
)
}
}
render(<LanguageDropdown />, document.getElementById('root'));
when you bind the handler in the onClick event where you are passing the value to the handler, then we have to pass that value from the event and collect it to get that value.
I encapsulated some HTML code to a extra class and want to hand over a function to it now.
The parent class looks like this:
class Home extends React.Component {
doSomething = id => {
console.log(id);
// here are some fetch operations only available in Home component
};
render() {
return (
<Child doSomething={() => this.doSomething} />
)
}
}
my Child component then looks like this:
const id = 3;
const Child = ({doSomething}) =>
(
<Button onClick={doSomething(id)}>Click</Button>
);
export default Child
I was trying around with different solutions but either I get no result or the onClick function is called when the Home component is rendered instead of when clicking on the button.
I want the function to be executed when the button is clicked. And the id parameter should be handed over as well. I can't have the function in the Child component itself since I have to use some redux actions in it which are not available in the child class.
I know this is not a too difficult question but I'm still a noob with JavaScript..
Edit: I accomplished having the event parameter inside my function but I wonder how to access the id with it. I can't simply add a prop to the Button element since it does not allow that.
Thanks in advance for your help,
Erik
You need to bind method in constructor and pass it to child component
class Home extends React.Component {
constructor() {
this.doSomething = this.doSomething.bind(this);
}
doSomething(id) {
console.log(id);
// here are some fetch operations only available in Home component
}
render() {
return <Child doSomething={this.doSomething} />
}
}
And in Child
const Child = ({doSomething}) =>
(
<Button onClick={() => doSomething(id)}>Click</Button>
)
I think you need something like this:
this.doSomething.bind(this);
It binds this as the first argument of your function, which is needed when you pass a class method as a reference. When doSomething is called in the child component, this will reference the parent component.
First of all your jsx is wrong. Your are missing
render() {
return ...;
}
There is no valid JSX Button
<Button onClick={doSomething(id)}>Click</Button>,
use <button> tag instead.
Here is working example.
const element = <h1>Hello, world</h1>;
class Home extends React.Component {
doSomething = id => {
console.log(id);
// here are some fetch operations only available in Home component
};
render() {
return <Child doSomething={() => this.doSomething('do something input')} />;
}
}
class Child extends React.Component {
constructor(props) {
super(props);
//console.log(props);
}
render() {
return <button onClick={this.props.doSomething.bind(this)}>Click</button>;
}
}
ReactDOM.render(
<Home />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.js"></script>
<div id="root"></div>
You probably need to pass the id when you are defining the fat arrow function
class Home extends React.Component {
doSomething(id) {
console.log(id);
}
render() {
return <Child doSomething={(id) => this.doSomething(id)} />
}
}
Firstly, in Home component use arrow function as doSomething prop to preserve correct context (alternatively you can use bind in component constructor):
class Home extends React.Component {
doSomething(id) {
console.log(id);
// here are some fetch operations only available in Home component
}
render() {
<Child doSomething={() => this.doSomething()} />
}
}
and then use arrow function that will call passed function with given value as click handler in child component:
<Button onClick={() => doSomething(id)}>Click</Button>
I am familiar with Javascript function bind. But I don't understand why in following React.js snippet is this bind again to this. Has is something common with constructor, because this in constructor can have different values depending on usage?
Thank you in advance for replies
class QuotesLibrary extends React.Component {
constructor(props) {
super(props);
this.search = debounce(this.search.bind(this), 300);
}
search(searchTerm) {
this.props.relay.setVariables({searchTerm});
}
render() {
return (
<div className="quotes-library">
<SearchForm searchAction={this.search} />
<div className="quotes-list">
{this.props.library.quotesConnection.edges.map(edge =>
<Quote key={edge.node.id} quote={edge.node} />
)}
</div>
</div>
)
}
}
What this.search.bind(this) does it that it is binding the key this inside to the function to the context of your React Component and what it basically means is that whenever you try to access a property of the React Component, you can access it like this.props since this will then refer to the React Component's context and not the function itself.
The significance of this.search before bind is that it is trying to access the function search which is in the context of the React Component and hence you are only binding it once and not twice.
I hope I was able to explain the situation properly
You shouldn't use Function.bind(this) : you should use arrow function. Arrow functions are bind to the class (so to the component).
class QuotesLibrary extends React.Component {
constructor(props) {
super(props);
this.search = debounce(this.search, 300);
}
search = (searchTerm) => {
this.props.relay.setVariables({searchTerm});
}
render() {
return (
<div className="quotes-library">
<SearchForm searchAction={this.search} />
<div className="quotes-list">
{this.props.library.quotesConnection.edges.map(edge =>
<Quote key={edge.node.id} quote={edge.node} />
)}
</div>
</div>
)
}
}
Here's an example of how the difference works -
As you can see, the first call will log 'undefined' and the second one will log 'Bar', because the 1st call wasn't binded, and calling functions indirectly (as promise results or as callbacks) doesn't keep the reference to this when it runs - bind tells it what its this is referring to.
function debounce(fn, to) {
setTimeout(fn)
}
class Foo {
constructor () {
this.fullName = 'Bar'
}
speak () {
console.log("My name is", this.fullName)
}
test () {
debounce(this.speak, 1000) // undefined
debounce(this.speak.bind(this), 2000) // "Bar"
}
}
let foo = new Foo()
foo.test()
Why are you saying "again"? You only bind it once, not twice.
debounce from _underscores library takes a function and returns another, therefore to get the this context in the search function you need to bind it to the search.
It's the exact same as binding functions normally in the constructor.
I'm trying to follow the no-bind rule for React using the pattern that they have recommended with ES6 classes:
class Foo extends React.Component {
constructor() {
super();
this._onClick = this._onClick.bind(this);
}
render() {
return (
<div onClick={this._onClick}>
Hello!
</div>
);
}
_onClick() {
// Do whatever you like, referencing "this" as appropriate
}
}
However, when I need to pass arguments in to _onClick, what needs to change?
I've tried something like:
import {someFunc} from 'some/path';
class Foo extends React.Component {
constructor() {
super();
this._onClick = this._onClick.bind(this, a, b);
}
render() {
const {
prop1,
prop2
} = this.props;
return (
<div onClick={this._onClick(prop1, prop2}>
Hello!
</div>
);
}
_onClick = (a, b) => {
someFunc(a, b);
}
}
However, this does not work. What needs to be altered?
The call to bind in the constructor should only pass this as a single argument.
this._onClick = this._onClick.bind(this);
Here you are overwriting the property this._onClick with a new one that has the correct this bound. If your function takes two arguments, then you should pass those as normal at call time.
Passing additional arguments to bind means that the function returned already has those arguments supplied - in your attempt the _onClick function will always have its first two arguments undefined, as a and b have no value in the constructor.
Now that you have bound this to your function, you can access this.props from within there, rather than having to pass arguments:
import {someFunc} from 'some/path';
class Foo extends React.Component {
constructor() {
super();
this._onClick = this._onClick.bind(this);
}
render() {
return (
<div onClick={this._onClick}>
Hello!
</div>
);
}
_onClick() {
const {
prop1,
prop2
} = this.props;
someFunc(prop1, prop2);
}
}
You should use partial application. Basically you initialise your onClick function with the parameters you want, and the onClick function will return a new function to be called when the div is clicked.
import {someFunc} from 'some/path';
class Foo extends React.Component {
render() {
return (
<div onClick={this._onClick(prop1, prop2)}>
Hello!
</div>
);
}
_onClick = (a, b) => {
return () => someFunc(a, b);
}
}
PS: this only applies if your parameters a and b are not part of your this.props, if they are then you should just do as Tom Fenech said.
To answer your question there is nothing special you have to do in order to pass arguments to your this._onClick function.
the proper revised code will be:
class Foo extends React.Component {
constructor() {
super();
this._onClick = this._onClick.bind(this);
}
render() {
return (
<div onClick={() => this._onClick(1, 2)}>
Hello!
</div>
);
}
_onClick = (a, b) => {
console.log(a, b);
}
}
Secondly, the way you are calling this._onClick is not the right way to invoke a function on click.
Right now what is happening that on each render process your function is getting called because you didn't pass the function as an argument rather you invoked that function and assigned its returned value to the onClick prop.
you have to do this like:
render() {
return (
<div onClick={() => this._onClick(prop1, prop2)}>
Hello!
</div>
);
}
By Invoking your function this way you ensure the this._onClick will get called when click event occurs.
Another method is to use Babel stage 1 autobind and skip the constructor.
import {someFunc} from 'some/path';
class Foo extends React.Component {
_onClick = () => {
const {
prop1,
prop2
} = this.props;
someFunc(prop1, prop2);
}
render() {
return (
<div onClick={this._onClick}>
Hello!
</div>
);
}
}