In this example for a controlled textarea, it shows how to set an initial value and then update the value onChange. How can you clear this initial value when the field is focused for the first time without clearing any further input from the user.
Setting the initial value:
this.state = {
value: 'Please write an essay'
};
I assume you would do something like:
<textarea value={this.state.value} onChange={this.handleChange} onFocus={this.handleFocus} />
Then have:
handleFocus(event) {
this.setState({value: ''});
}
Although this isn't working. Any advice?
Codepen: https://codepen.io/anon/pen/KZVeWB?editors=0010
If you pass a function to a component, like an event handler, the "this" capture is lost. When the textarea calls your event handler, "this" will not refer to the component where that function was defined. I think it will actually refer to the event handler function its self.
The usual way of getting around this is binding 'this' to the event handler:
onFocus={this.onFocus.bind(this)}
You can also define your methods as lambda member variables if you're using ES7:
class MyComponnet {
onFocus = (e) => { ... }
render() {
return <textarea onFocus={this.onFocus} />
}
}
This works because lambdas in js automatically capture everything around them. it looks a bit cleaner.
Also, you should consider using a placeholder attribute instead:
https://www.w3schools.com/tags/att_textarea_placeholder.asp
You missed to bind your handleFocus method in a constructor function
this.handleFocus = this.handleFocus.bind(this)
Related
I am writing a react application, and for some reason I can not wrap my head around this issue. Below is a snippet, the only thing that should be needed:
onFirstNameChange(event: any){
console.log(event.target.value)
// this.setState({
// firstname: event.target.value
// })
}
The commented out code will not run, it says it can not read properties of undefined. However when I log the events value it does it perfectly. Any ideas on why this is happening? It is an onchange event. It is also deeply nested, however the value does make it back.
React components written in an ES6 class, do not autobind this to the component's methods. There are 2 solutions primarily. You may use choose either:
Either explicitly bind this in constructor
constructor(props) {
super(props);
// rest of code //
this.state = {
firstname: '',
};
// rest of code //
this.onFirstNameChange = this.onFirstNameChange.bind(this);
}
Or use ES6 Arrow Function
onFirstNameChange = (event: any) => {
console.log(event.target.value);
this.setState({
firstname: event.target.value
});
}
As Brian stated, I also believe the error saying that it cannot read property of undefined, is likely saying it cannot read property setState of undefined, because "this" is undefined.
This is most likely caused by providing the onFirstNameChange handler without leveraging a closure, bind, or arrow function to bind the value of this to the "this" value you are expecting.
My guess is your code leveraging the on change handler looks like the following:
<input type="text" value={this.state.value} onChange={this.onFirstNameChange} />
You can refer to the "Handling Events" page (link here) of the React documentation, you will find the following about midway down the article:
You have to be careful about the meaning of this in JSX callbacks. In
JavaScript, class methods are not bound by default. If you forget to
bind this.handleClick and pass it to onClick, this will be undefined
when the function is actually called.
This is not React-specific behavior; it is a part of how functions
work in JavaScript. Generally, if you refer to a method without ()
after it, such as onClick={this.handleClick}, you should bind that
method.
If calling bind annoys you, there are two ways you can get around
this. If you are using the experimental public class fields syntax,
you can use class fields to correctly bind callbacks.
SOLUTIONS: I've included examples of the 3 possible solutions below to bind the value of this, depending on your preference:
Option 1 - Assuming this is a class based component, which I am based on the syntax shown, you can bind the method in the constructor:
constructor(props) {
super(props);
this.onFirstNameChange.bind(this);
}
Option 2 - Update method definition to public class fields syntax with an arrow function to bind "this": (See here)
onFirstNameChange = (event: any) => {
console.log(event.target.value)
this.setState({
firstname: event.target.value
})
};
Option 3 - Update onChange callback with anonymous arrow function to bind this value:
<input type="text" value={this.state.value} onChange={() => this.onFirstNameChange} />
Note on option 3 from React Docs:
The problem with this syntax is that a different callback is created
each time the LoggingButton renders. In most cases, this is fine.
However, if this callback is passed as a prop to lower components,
those components might do an extra re-rendering. We generally
recommend binding in the constructor or using the class fields syntax,
to avoid this sort of performance problem.
Very simple. I am making a button to change the state of my parent based on what is entered into an input bar. After the user types a code in and clicks enter a for loop is called which iterates through an array to make sure that the code the user entered is present in the array. If the code is present, this.setState is called and the parent's state is changed.
However, after passing the function from the parent to the button component, if I even type in a string that is in the array into the input field I automatically get an Error: Maximum update depth exceeded saying that the component is repeatedly calling setState -- however, that shouldn't even be possible since I have yet to click the button so the for loop shouldn't even be in use. (well it might be possible I have no clue why it is doing that)
This is the parent:
constructor(props){
super(props);
this.state = {
roomList: [],
activeRoom: undefined
};
this.onUpdateRooms = this.onUpdateRooms.bind(this);
}
//function for changing state
onJoinRoom(roomCode) {
for(let i = 0; i < this.state.roomList.length; i++){
if (this.state.roomList[i].roomCode === roomCode) {
this.setState({activeRoom: roomCode});
console.log('Found')
}
}
}
//within the render
<JoinButton onJoinRoom={this.onJoinRoom}/>
This is my button class:
constructor (props) {
super(props)
this.state = {
enteredCode: ''
}
}
handleInput(e) {
this.setState({enteredCode: e.target.value});
}
handleClick() {
this.props.onJoinRoom(this.state.enteredCode);
}
render() {
return (
<div>
<input
className="roomCodeInput"
type='text'
placeholder='Enter A Room Code'
onChange={this.handleInput.bind(this)}
value={this.state.enteredCode}
/>
<button className="join" onClick={this.handleClick(this)}>JOIN</button>
</div>
);
}
I did a bit of research and people say that one reason for this error is for calling the function within the render method(ie. onClick={this.props.function()} instead of .function without the parenthesis). However, I am using handleClick and binding it so I don't believe my problem is the same. In addition, I need to pass the function parameters so the parenthesis are necessary.
Really confused right now, would love some help :/
First thing you need to do is bind your functions to the corresponding components in the constructors because when you do things like set state or use events. React doesn't know what context to do these things on.
this.onJoinRoom = this.onJoinRoom.bind(this); will bind the function to the parent class.
And you'll need to do the same with button class
this.handleClick = this.handleClick.bind(this);
this.handleInput = this.handleInput.bind(this);
And then simply call the functions defined in the constructors; without brackets.
<div>
<input
className="roomCodeInput"
type='text'
placeholder='Enter A Room Code'
onChange={this.handleInput}
value={this.state.enteredCode}
/>
<button className="join" onClick={this.handleClick}>JOIN</button>
</div>
I think it might be because you are trying to bind this while passing function to onChange event.
Instead of that, I suggest you use arrow functions, so you need not worry about binding to this.
Just change your handleInput function as below
handleInput = (e) => {
this.setState({enteredCode: e.target.value});
}
And then you can simply pass handleInput to your event handler like this
<input
className="roomCodeInput"
type='text'
placeholder='Enter A Room Code'
onChange={this.handleInput} //need not bind this
value={this.state.enteredCode}
/>
Also inside your parent, you haven't bind this to onJoinRoom handler so you need to convert it to arrow function or you can bind to this inside constructor.
See this question for difference between the arrow and normal function-
Are 'Arrow Functions' and 'Functions' equivalent / exchangeable?
I have an input tag in render like this:
<input id="time" type="time">
and I need dynamimically add value attribute
How can I do this in React? Thanks in advance
Yes, you can do. e.g. props is an object which contains props or properties that you want to add based on some condition then you can something like
const props = { id: 'time', type: 'time' };
if (condition1) {
props.value = 'some value';
}
if(condition2) {
props.abc = 'some other value';
}
<input {...props} >
You should add an onchange attribute on the input which changes the state of your component. This will look something like this:
<input type="text" value={this.state.value} onChange={this.handleChange} />
The handleChange method should then look something like this:
handleChange = (event) => {
this.setState({value: event.target.value});
}
For more information check out the following article: https://reactjs.org/docs/forms.html
You would need to set the state of React. So...
this.setState({
myValue: newValue
})
Then, inside render:
<input id="time" type="time" value={this.state.myValue}>
This assumes you have your state setup with a constructor. Which is a whole other can of worms.
You shouldn't dynamically add or remove a "value" field. When you create a React input, it must be either "controlled" or "uncontrolled" through its whole lifespan. Changing it will make React yell a warning on the console.
React understads an input is meant to be uncontrolled if value is not present or undefined, so you need to at least set it to "" in order to achieve a controlled empty input.
"Controlled" means react controls its value. Ex: For the value to be changed, you'd need to notify react of the change (through onChange + setState) and then make it change its value;
"Uncontrolled" means react can't control the input's value, and you'd read and change the value through regular DOM ways (ex: input.value).
That being said, in order to dynamically change the presence of any element properties (props), you can use the "object spread" operator.
function render() {
const custom = { value: 2, color: randomColor() }
return <Element {...custom}/>
}
I guess you are rendering the tag within a render() function within a JSX expression (otherwise you would have added it through normal Javascript or JQuery).
Therefore the JSX expression will have something like:
<input id="time" type="time" value={yourValue}>
making sure that yourValue is in scope within the context of execution of your render() in your ReactComponent class or in the props. Alternatively it could be in the state.
Say I have a function:
handleChange = (e) => {
this.setState({ [e.target.id]: e.target.value });
}
What is the difference between the following:
1.
<FormControl value={this.state.password} onChange={this.handleChange} />
<FormControl value={this.state.password} onChange={(e) => this.handleChange(e)} />
The second case an anonymous function is created which executes the handleChange method and and thereby providing it the context.
Everytime the React component renders, a new function is created in the second and not in the first case since the same reference of handleChange method is being provided to the handler.
You might also want to look at how arrow function in render achieve context binding
Assuming your event handler is written like so in your class
handleChange = (e) => {
this.setState({ [e.target.id]: e.target.value });
}
Let us go to the first example that you have mentioned.
<FormControl value={this.state.password} onChange={this.handleChange} />
Over here, for every change you are passing the memory reference of the handleChange function, and to it the event object is being passed.
Going to the second method.
<FormControl value={this.state.password} onChange={(e) => this.handleChange(e)} />
Here you are creating a new anonymous function, which takes the event object as a parameter, every time an event change occurs. This drastically increases garbage collection if you have large list items.Adding an arrow function in this case is redundant as the context is already bound due to the way you wrote you handleChange method initially. As a perf tip, if you are using arrow functions in your classes, use option 1 for event handlers.
Using arrow function in render may cause some performance issues.
I'd suggest you to use arrow function in class property, but you must use stage-2 features.
Here you'll find a nice comparison between the options:
https://medium.freecodecamp.org/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56
In the first case you are using handleChange as event handler.
In the second case you are using a new function as event handler, which in turn calls handleChange.
The difference is that there will be two function calls in the second example. Otherwise they are the same.
In other words: there is no need to use the second form, and it can even be disadvantageous for rerendering.
We can bind our event handlers in class constructor:
we can now access to this inside the event handle
class MyClass extends Component {
constructor(props) {
super(props)
this.handleChange = this.handleChange.bind(this)
}
handleChange(){
//you can now access "this" inside handlechange
}
}
Looks fine. When we add more event handlers to our class, code should look similar to this:
import React, { Component } from 'react'
import { MyInput, MyAnotherInput } from 'myInputs'
class MyComponent extends Component {
constructor(props) {
super(props)
this.handleChange = this.handleChange.bind(this)
this.handleClick = this.handleClick.bind(this)
this.handleKeyPress = this.handleKeyPress.bind(this)
}
handleChange(e) {
e.preventDefault()
}
handleClick(e) {
e.preventDefault()
}
handleKeyPress(e) {
e.preventDefault()
if (e.nativeEvent.keyCode === 13) {
console.log('This is enter!')
}
}
render() {
return (
<div>
<MyInput
onChange={ this.handleChange }
onClick={ this.handleClick }
onKeyPress={ this.handleKeyPress }
/>
<MyAnotherInput
onChange={ this.handleChange }
onClick={ this.handleClick }
onKeyPress={ this.handleKeyPress }
/>
</div>
)
}
}
This is, what we can do with Babel compiler with es2015 as preset configuration.
Event handlers with arrow functions
As you have probably seen, when we create event handler method, we always need to add this to constructor, to bind this. Quite tiresome. To be honest, there is no sense to create constructor method only for binding your methods. There should be another solution, and there is.
All what you need is to install stage-1 Babel preset and use arrow functions. If you don’t know, how to do this, go to Babel documentation, it’s very good.
In our case instead of binding methods to this we can writ something like this:
render() {
return(<MyInput onChange={ (e) => this.handleOnChange(e) } />)
}
We have created new anonymous function, which automatically bind this,
that’s why we don’t need to use .bind() method. We have still the same
methods in class, and new arrow functions as wrappers in callbacks
properties.
This is still not perfect solution, because we need to update parameters in arrow function wrappers and we create new instances each time when render method is triggered. Arrow functions in React properties are also not great idea.
When handling an event in JavaScript, the this context out of the box can be very confusing, you can read more about it in this excellent writeup.
Back to your question, the first way onChange={this.handleChange} does not guarantee the this context in handleChange() would always be the same component instance, in many cases, this would refer to the FormControl instance that emits the onChange event.
The second way uses arrow syntax, it would guarantee this would always be the React component instance that handles the event.
In short, using arrow syntax for event handling is preferred in React component classes because it guarantees a consistent this context.
I'm having difficulty understanding why create-react-app is unable to compile, telling me that error 'updateWord' is not defined no-undef. I'm fairly new to React with ES6. Normally I would write a component like const App = React.createClass({ }); but I've decided to try out some syntactical sugar instead.
I have parent component App and a child component Input:
class App extends Component {
constructor(props) {
super(props);
// all other code omitted...
}
handleInput(input) {
console.log(`handle: ${input}`);
updateWord(input);
// this also causes an error
// this.updateWord(input);
}
updateWord(input) {
console.log(`update ${input}`);
// why isn't this defined?
}
render() {
return (
<div className="App">
<Input onInput={this.handleInput} />
</div>
);
}
}
class Input extends Component {
handleInput(e) {
let input = e.target.value;
this.props.onInput(input);
}
render() {
return (
<form>
<input onChange={this.handleInput.bind(this)} />
</form>
);
}
}
I've tried changing to this.updateWord(input); instead of updateWord(input) but to no avail. I get:
"App.js:55 Uncaught TypeError: this.updateWord is not a function"
Normally when I implement a similar pattern (with ES5) to what I'm doing now I have no difficulties. For example:
const App = React.createClass({
getInitialState: function() {
// all other code omitted...
},
handleInput: function(input) {
console.log(`handle: ${input}`);
this.updateWord(input);
},
updateWord: function(input) {
console.log(`update ${input}`);
// In theory, this implementation would not cause any errors?
},
render: function() {
return (
<div className="App">
<Input onInput={this.handleInput} />
</div>
);
}
}
The problem is that when you do this.updateWord(...) in this.handleInput, this refers to the Input component. Let me illustrate the problem:
When you set the onInput handler, like so:
onInput={this.handleInput}
Here, since your Input component is calling the function, this refers to the Input component. This is due to the line:
this.props.onInput(input);
The Input component is calling handleInput. That means, in your handleInput function, the this context is Input. Consider the line:
this.updateWord(input);
in the handleInput function. Here you call this.updateWord, but since this is Input, it tries to call updateWord from Input which does not exist, thus throwing the error.
The solution is to explicitly bind the this context as the class (App component) instead of the Input component, using either Function.prototype.bind or an arrow function. From the documentation:
The bind() method creates a new function that, when called, has its this keyword set to the provided value
You can apply it like so:
onInput={this.handleInput.bind(this)}
Or more preferably in the constructor:
this.handleInput = this.handleInput.bind(this);
With the second option you may then do:
onInput={this.handleInput}
(This is more preferable as binding in the render method will create a new function every time on render, which isn't preferred).
The this context in the line above is the class. Since you bind this, the class will be correctly used as this context in the function and executing this.updateWord will invoke the method in the class.
An even more preferable way is to use arrow functions instead of regular ES6 methods. From the documentation:
An arrow function expression has a shorter syntax compared to function expressions and does not bind its own this, arguments, super, or new.target.
We can apply this by assigning handleInput to an arrow function instead of a regular method:
handleInput = (input) => {
console.log(`handle: ${input}`);
this.updateWord(input);
}
This will eliminate the use of bind completely and instead, use arrow functions. Since arrow functions don't bind their own this, it means this refers to the enclosing context. In the example above, a method is not used thus this refers to the class (the enclosing context). That will correctly call the class method updateWord, and consequently, you need not change the onInput event handler if you go this route.