This question already has answers here:
Unable to access React instance (this) inside event handler [duplicate]
(19 answers)
Closed 6 years ago.
I'm pretty confident i'm doing this wrong, i'm unable to console.log this.state.greeting however if I reference this.state.greeting inside the return statement it works, i'm confused why it doesn't work within the class method
class Test extends React.Component {
constructor (props) {
super(props)
this.state = {
greeting: 'test'
}
}
greeting () {
console.log(this.state.greeting)
}
render () {
return (
<p onClick={this.greeting}>test</p>
)
}
}
export default Test
You need to bind it. Here are two options:
class Test extends React.Component {
constructor (props) {
super(props)
this.state = {
greeting: 'test'
}
}
greeting () {
console.log(this.state.greeting)
}
render () {
return (
<p onClick={this.greeting.bind(this)}>test</p>
)
}
}
// OR THIS
class Test extends React.Component {
constructor (props) {
super(props)
this.state = {
greeting: 'test'
}
this.greeting = this.greeting.bind(this);
}
greeting () {
console.log(this.state.greeting)
}
render () {
return (
<p onClick={this.greeting}>test</p>
)
}
}
There are actually two tricks to this one. You can either use the bind function in your constructor like so:
this.greeting = this.greeting.bind(this);
or if you have babel setup correctly with es6 and presets then you can do it a better way by using anonymous lambdas. Inside your .babelrc file it should look like this:
{
"presets": [
"react",
"es2015",
"stage-1"
]
}
and have the proper dependencies installed then you can use the es6 functions like this:
class Test extends React.Component {
constructor (props) {
super(props);
}
greeting = () => {
console.log(this.state.greeting)
}
render = () => {
return (
<p onClick={this.greeting}>test</p>
);
}
}
export default Test
Personally I love the second option. It doesn't bloat up your constructor, and the anonymous lambdas are nicer to type than function every time.
Related
I was following a YouTube tutorial on eventHandling when I got confused with the implementation of this keyword.
In the code below, the this keyword inside of clickHandler function gives the value of undefined. The instructor said that it is because that's how JavaScript works. But when I searched online I found out that this keyword when used inside a function of a class, points to the object itself.
This might be a stupid question to ask but since I am new to JavaScript any help will be appreciated
class EventBind extends Component {
constructor(props) {
super(props);
this.state = {
message: "Hello",
};
}
clickHandler() {
// this.setState({
// message : 'Goodbye'
// })
console.log(this);
}
render() {
return (
<div>
<div>{this.state.message}</div>
<button onClick = {this.clickHandler}>Click</button>
</div>
);
}
}
This is cause you have not bound the clickHandler to this.
Try below code
class EventBind extends Component {
constructor(props) {
super(props);
this.clickHandler = this.clickHandler.bind(this);
...
}
clickHandler() {
...
}
...
}
See here for more info: https://reactjs.org/docs/faq-functions.html
I am trying to call function outside from class and update the state of class. Is this correct way ?
function myFunc() {
this.Test("test")
}
class Notification extends Component {
constructor(props) {
super(props);
this.state = {
demoState:''
};
}
Test(data){
this.setState({
demoState:data
})
}
render(){
return(<div/>)
}
}
You haven't provided function usage in your example.
It's correct way, that's how the most function works. But don't tease react.js by using this argument - just pass an argument to myFunc
YES pass this an argument to myFunc.
function myFunc(this /* <----- */) {
this.Test("test")
}
Then call myFunc from inside of class like this:
myFunc(this);
May be, you need to pass object of that class to change the state. Have a look at myFunc & Notification.Test function changes.
function myFunc() {
let notification = new Notification({});
notification.Test("test");
console.log(notification.state);
}
class Notification extends Component {
constructor(props) {
super(props);
this.state = {
demoState: ''
};
}
Test(data) {
this.state = {
demoState: data
};
}
render() {
return ('<div/>')
}
}
I'm learning React 16.3, and it's new Context API. In particular Updating Context from a Nested Component. In their example they set a method that is defined in the constructor rather than a standard method.
class App extends React.Component {
constructor(props) {
super(props);
// What is the benefit of doing this here?
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
this.state = {
theme: themes.light,
toggleTheme: this.toggleTheme,
};
}
render() {
// The entire state is passed to the provider
return (
<ThemeContext.Provider value={this.state}>
<Content />
</ThemeContext.Provider>
);
}
}
Everything I've read regarding lifting state up and passing methods down to children has been done using the below pattern. Why is the above preferred over the below? Are there any differences?
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
toggleTheme: this.toggleTheme,
};
this.toggleTheme = this.toggleTheme.bind(this);
}
// Could it be done here?
toggleTheme() {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
render() {
// The entire state is passed to the provider
return (
<ThemeContext.Provider value={this.state}>
<Content />
</ThemeContext.Provider>
);
}
}
If you use the first approach which is defining the method inside the constructor like this
constructor() {
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
}
Then when your component usesthis.toggleTheme as a callback, you don't have to bind its this reference to the current component in which it is defined, e.g. this.toggleTheme = this.toggleTheme.bind(this), on the other hand, if you define toggleTheme as a method outside the constructor as in your second example, and if toggleTheme is passed as a callback, you will get "setState is not defined" or something like that when toggleTheme is invoked
Also, with the first approach toggleTheme is added as a instance property to the component class meaning each component instance will have a separate copy of toggleTheme, whereas the second approach will add it to the prototype of the component class which is better in terms of memory consumption because all component instances will share that method on the prototype
The difference between this two approaches:
class MyComponenet extends React.Component {
constructor(props) {
super(props);
this.method = () => {
console.log('Method');
}
}
render() {
return null;
}
}
... and ...
class MyComponenet extends React.Component {
method() {
console.log('Method');
}
render() {
return null;
}
}
Is that the first approach defines the method with the arrow notation which automatically binds the function's this to be the instance of the component class while the other doesn't.
You could change the second example to:
class MyComponenet extends React.Component {
method = () => {
console.log('Method');
}
render() {
return null;
}
}
This would be the same as the first example, but keep in mind you have to enable your transpiler option that allows this syntax.
Well here I want to use one method to another component, And for that I found a way through composition.
And this is what I did for that
file1.js
import ProductList from '../../views/Products/ProductList';
class CloseableTab extends Component {
constructor() {
super();
this.tpItem = () => {
console.log("hello, item clicked");
};
}
render() {
return (
<div>
<ProductList
itemChange={this.tpItem} />
</div>
);
}
}
export default CloseableTab;
Then in productList I want to call the "tpItem" method by calling itemChange in prop.
Though before that I tried to console the 'prop' of product list. So, it shows me null object in the console. And for that I used the code below:
ProductList.js
export default class ProductList extends Component {
constructor() {
super();
};
render() {
console.log(this.props);
return { }
}
}
So, this gives me null object in the console.
I'll appreciate your help, thanks.
Did you make constructor props enabled ?
Just pass props parameter in constructor
constructor(props) {
super(props)
}
The constructor for a React component is called before it is mounted.
When implementing the constructor for a React.Component subclass, you
should call super(props) before any other statement. Otherwise,
this.props will be undefined in the constructor, which can lead to
bugs.
Its not ideal to define functions in the constructor of the component, you can declare them outside of constructor and pass them down, also, in ProductList you are trying to render an object which isn't supported. if you don't want to return anything use return null.
Below code works as expected.
class CloseableTab extends Component {
constructor() {
super();
this.tpItem = () => {
console.log("hello, item clicked");
};
}
render() {
console.log(this.tpItem);
return (
<div>
<ProductList
itemChange={this.tpItem} />
</div>
);
}
}
class ProductList extends Component {
render() {
console.log(this.props);
return null
}
}
However you must write it like
class CloseableTab extends Component {
tpItem = () => {
console.log("hello, item clicked");
};
render() {
console.log(this.tpItem);
return (
<div>
<ProductList
itemChange={this.tpItem} />
</div>
);
}
}
Working sandbox
I'm learning React and I'm not sure how to setup this pattern. It could be something really easy I'm just missing.
I have a main component that controls state. It has all of the functions to update state and passes these down to child components via props. I've simplified the code to focus on one of these functions.
Here's the component now, all works as it should:
ManageMenu.js
import React from 'react'
class ManageMenu extends React.Component {
constructor() {
super()
this.toggleEditing = this.toggleEditing.bind(this)
// Set initial state
this.state = {
menuSections: []
}
}
toggleEditing(id) {
const menuSections = this.state.menuSections
menuSections.map(key => (key.id === id ? key.details.editing = id : ''))
this.setState({ menuSections })
}
render() {
return (
...
)
}
}
export default ManageMenu
The toggleEditing is passed via props to a child component that uses it to render an editing form if the edit button is clicked.
I have about 10 of these different functions in this component and what I would like to do is move them to an external lib/methods.js file and then reference them. Below is the code I would like to have, or something similar, but React doesn't like what I'm doing. Throws a syntax error:
Failed to compile.
Error in ./src/components/ManageMenu.js
Syntax error: Unexpected token
toggleEditing(id, menuSectionId, this.state, this)
Here is what I would like to do...
lib/methods.js
const toggleEditing = function(id, state, that) {
const menuSections = state.menuSections
menuSections.map(key => (key.id === id ? key.details.editing = id : ''))
that.setState({ menuSections })
}
module.exports = {
toggleEditing
}
And then in my component:
ManageMenu.js
import React from 'react'
import { toggleEditing } from '../lib/methods'
class ManageMenu extends React.Component {
constructor() {
super()
// Set initial state
this.state = {
menuSections: []
}
}
toggleEditing(id, this.state, this)
render() {
return (
...
)
}
}
export default ManageMenu
Any help is appreciated, thanks!
Thanks to #Nocebo, the answer on how to externalize functions is here:
Externalise common functions in various react components
In my particular situation,
I need to remove the “floating” toggleEditing(id, this.state, this) call in the middle of nowhere. Update: This error happens “because it is invoking a method within a class definition.” (see Pineda’s comment below)
Remove the leading this. on the right side of the this.toggleEditing statement in constructor()
Update the function in lib/methods.js to remove the state and that variables since its bound to this in the constructor()
See updated code below.
ManageMenu.js
import React from 'react'
import { toggleEditing } from '../lib/methods'
class ManageMenu extends React.Component {
constructor() {
super()
this.toggleEditing = toggleEditing.bind(this)
// Set initial state
this.state = {
menuSections: []
}
}
render() {
return (
...
)
}
}
export default ManageMenu
lib/methods.js
const toggleEditing = function(id) {
const menuSections = this.state.menuSections
menuSections.map(key => (key.id === id ? key.details.editing = id : ''))
this.setState({ menuSections })
}
module.exports = {
toggleEditing
}
You're error arises because you are invoking toggleEditing in your ManageMenu.js class definition rather than defining a function.
You can achive what you want by setting a local class member this.toggleEditing to the bound function returned by the .bind method and do so within the constructor:
import React from 'react'
import { toggleEditing } from '../lib/methods'
class ManageMenu extends React.Component {
constructor() {
super()
this.state = {
menuSections: []
}
// bind external function to local instance here here
this.toggleEditing = toggleEditing.bind(this);
}
// don't invoke it here, bind it in constructor
//toggleEditing(id, this.state, this)
render() {
return (
...
)
}
}
export default ManageMenu