ReactJs print value of input field - javascript

I'm trying to print instantly my input value in the render function.
In the documentation of the concept of state and lifecycle in a React component, I see the use of a constructor with a super(props) as well as this.state.
I get the error below when trying same;
Uncaught TypeError: Cannot read property 'state' of undefined
Below is my code;
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
text: ''
};
};
handleChange(event) {
this.setState({
text: event.target.value
});
};
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.text}.</h2>
<input type="text" onKeyUp={this.handleChange} />
</div>
);
}
}
How can I fix it?

when you call a function like that, it is called by the window, not by your react object.
To make the function be bound to your react object (and have the ability to use the setState method, you need to use this:
onKeyUp={this.handleChange.bind(this)}
this will bind it to your react object :)

You have to bind this to your event handler like this:
<input type="text" onKeyUp={this.handleChange.bind(this)} />
Working Example: https://codepen.io/shanedaugherty/pen/ALwAzL

this.handleChange = this.handleChange.bind(this);
You can bind it like this in constructor and it will work, as you have to bind this to your react function.

You use value as an attribute.
value={this.state.text}
OR

Related

Obtain value from InputText using React.createRef()

Instead of re-rendering the entire component-tree whenever "<InputText style{...}>" is changed, I am trying to use refs in my Class Component. (I am using React Native with Expo managed workflow.)
Using refs, the typed text appears as it should in the InputText field.
But, when a button is pressed, the value of the typed text (value of the InputText) should be console logged, however it is not.
export class Feed extends Component {
constructor(props){
super(props);
this.state = {
//some state variables
}
this.myTextFromInput = React.createRef()
}
I started by creating the myTextFromInput ref (above).
<TextInput
style={{height:100}}
ref={this.alias}
placeholder="Input Text Here"
/>
I then used the myTextFromInput ref in the InputText component. And lastly, the button!
<Button onPress={()=>console.log(this.myTextFromInput.current.value)}>Press me!</Button>
This gives me undefined. I have also tried this.myTextFromInput.value and a .getText() method which is outdated.
How can I obtain the inputed text?
UPDATE:
Terminal log undefined. But snack works fine!?
You aren't passing the correct reference to TextInput, it should be this.myTextFromInput not this.alias, take a look:
export class Feed extends Component {
constructor(props){
super(props);
this.state = {
//some state variables
}
this.myTextFromInput = React.createRef()
// bind the method to the component instance
this.logInputText = this.logInputText.bind(this)
}
logInputText() {
console.log(this.myTextFromInput.current.value)
}
render() {
return (
<View>
<TextInput
style={{height:100}}
// pass the correct reference here
ref={this.myTextFromInput}
placeholder="Input Text Here"
/>
<Button
onPress={this.logInputText}>
Press me!
</Button>
</View>
)
}
}
Also don't forget that whether you use a method instead of arrow function you've to bind it to the class instance, like I did. See this question and this example from react docs.
Update: React.ref on Android and iOS doesn't seems to work as the same way as it works on web, you can't get the value from input because the component doesn't provide this property, doing a console.log(this.myTextFromInput.current) you can see all the available properties. One solution from this question is to use TextInput from the package react-native-paper, as it provides the input value from the ref, or you could use the common state approach to store the input value, like so:
export class Feed extends Component {
constructor(props){
super(props);
this.state = {
myTextFromInput: ""
}
// bind the method to the component instance
this.logInputText = this.logInputText.bind(this)
}
logInputText() {
console.log(this.state.myTextFromInput)
}
render() {
return (
<View>
<TextInput
style={{height:100}}
// you don't need to use ref
placeholder="Input Text Here"
onChangeText={(text) => this.setState({myTextFromInput: text})}
/>
<Button
onPress={this.logInputText}>
Press me!
</Button>
</View>
)
}
}

Cannot read property 'someProperty' of undefined in react

I am working on an application where I pass variable values in a Navlink using state from one component to the other and then load those received values in input fields and click on submit button in that other component to do something with values. My values are received correctly and show up correctly when I alert them. But when I click submit button, it gives error,pointing at the constructor
TypeError: Cannot read property 'id' of undefined
Here is my code
class Parent extends React.Component{
constructor(props) {
super(props);
this.state={id:2}
}
render(){
return(
<NavLink
to={{
pathname: '/Child',
state: {
id: this.state.id
}
}}
>
Edit
</NavLink>
)
)
}
Where I receive the values
class Child extends React.Component{
constructor(props) {
super(props);
this.state = {id:this.props.location.state.id}
alert(this.props.location.state.id)//works fine
}
setId(e){
this.setState({id:e.target.value})
}
addOrEdit(){ //gives error
alert(this.state.id)
//do something
}
render(){
return(
<div>
<form>
<label>Id</label>
<input value={this.state.id} onChange={this.setId.bind(this)} type="text"/><br/>
<input type="submit" onClick={this.addOrEdit.bind(this)} ></input>
</form>
</div>
)
}
}
this.state = {id: this.props.location && this.props.location.state && this.props.location.state.id}
Should fix your issue that caused by times that this component called without this context or this line got excuted before location set.
(assuming you using withRouter for making location props be exist...)
Anyhow, and not related directly to your issue, it is bad practice to set initial value for state from props at constructor, consider manipulate state through life cycle either don't use state here and refer to props directly
I would suggest to just use arrow functions for setId and addOrEdit.
addOrEdit = (e) => {
// ...
}
And just call them:
onChange={this.setId}
onClick={this.addOrEdit}
https://medium.com/#machnicki/handle-events-in-react-with-arrow-functions-ede88184bbb
Also you are deriving state from prop.
It is better to just use the prop directly.
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html

React: why do you have to bind this method?

I'm reading this article on "Lifting State Up" in React. It defines the Calculator component as follows:
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input
value={temperature}
onChange={this.handleChange} />
<BoilingVerdict
celsius={parseFloat(temperature)} />
</fieldset>
);
}
}
In the line this.handleChange = this.handleChange.bind(this);, I'm wondering why we have to bind this.handleChange to this. It's used in the line onChange={this.handleChange}. Wouldn't this work the same even if we hadn't done that binding?
The this inside handleChange would refer to the method and not to the component instance (Calculator). Since handleChange does not have a setState method (the component does) we have to bind the correct this in the method. If you had another method that was not doing anything with this, then yes, you could skip the bind.
From the official docs:
If you need to have access to the parent component in the handler, you also need to bind the function to the component instance.
A way to circumvent this is to either use the fat arrow syntax (as in Dimitar's answer) or use the React Hook API
In other words (see comments):
constructor(props) {
super(props);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
// ^ this = handleChange. You cannot call setState on handleChange.
}
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
// ^ this = Calculator component. All React (class) Components have setState
}
This has to do with scopes, and is something that ES6 solves by implementing fat arrow functions.
Basically when you create a method inside of a class in JavaScript, that method does not instantly inherit this, so any reference to this will result in an error. To solve this, you need to bind the function to this which basically virtually passes down an instance of the class to the function as a parameter (if you look in the background).
If you want to avoid this binding, you can just use a fat arrow function like so:
handleChange = e => this.setState({[e.target.name]: e.target.value})
In that basic example, I referenced this without having bound the method to this and didnt get an error because fat arrow functions are automatically bound to this

Correct way to access value of an input initialized with a prop when button is clicked in react

I have a react component that consists of an input field and a button. When the button is clicked I want to run an update function that is also inherited from the parent controller. In the react documentation they have an onchange handler attached to this input and they get the new value of the input with the onchange event object. However in my case I get an event object describing the button, not the input field. What is the correct way to access the new input field value from handle click?
class QuoteButton extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick () {
this.props.onQuoteUpdate(//what should go here?)
}
render() {
const cost = this.props.cost;
return (
<div>
<Input value={cost}/>
<Button basic color='green' onClick={this.handleClick}>Submit Quote</Button>
</div>
);
}
}
If you a going to change input value in this component you need to use react states (if you don't use state management libraries such as mobx or redux). In most cases input have to be a controlled component.
After component was mounted add cost value to states. You also need appropriate handler for input.
P.S. You could use arrow functions to avoid binding handlers in constructor.
class QuoteButton extends React.Component {
constructor(props) {
super(props);
this.state = { inputValue: '' };
}
componentDidMount() {
this.setState({inputValue: this.props.cost});
}
handleClick = () => {
this.props.onQuoteUpdate(this.state.inputValue);
}
handleInputChange = event => {
this.setState({inputValue: event.target.value});
}
render() {
return (
<div>
<Input value={this.state.inputValue} onChange={this.handleInputChange} />
<Button basic color='green' onClick={this.handleClick}>Submit Quote</Button>
</div>
);
}
}
Hope it helps

react props undefined inside the constructor and exist inside the render

I'm trying to create a controlled text area.
class TextArea extends React.Component {
constructor(props) {
super(props);
this.state= {
text: this.props.initial
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
//some handle
}
render() {
return (
<textarea
value={this.state.text}
placeholder={this.props.initial}
onChange={this.handleChange}
/>
);
}
}
For some reason if I console.log the this.props.initial in the constructor I get an undefined.
But the placeholder works.
What I would like to do is to ditch the placeholder and set an initial value to that the user can edit and copy and interact with. (basically normal text and not a placeholder, but I cannot do that because it doesn't work)
What am I doing wrong?
Edit:
The way that I am passing props.initial to the textarea:
<TextArea
initial={this.state.json.initial}
text={this.state.json.text}
changeHandler={this.handleChange}
/>
I am getting the json from a $.getJSON call and I think that the textarea gets rendered before the json call is finished. Is there any way to run the render function only after the componentWillMount function?
Remove this from this.props in the constructor since you have access to props from its argument list.
class TextArea extends React.Component {
constructor(props){
super(props)
this.state = {
text: props.initial,
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event){
this.setState({ text: event.target.value })
}
render(){
return (
<div>
<div>Initial text: {this.props.initial}</div>
<textarea
value={this.state.text}
placeholder={this.props.initial}
onChange={this.handleChange}
/>
</div>
)
}
}
ReactDOM.render(
<TextArea />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
You have to garantee that this.props.inital exists:
{ this.state.json && this.state.json.initial &&
<TextArea initial={this.state.json.initial} text={this.state.json.text} changeHandler={this.handleChange}/>
}
the important part to understand is that the constructor already takes in the props as parameters so you can access props directly in the constructor as props. no need to access it via this.props as long as you are inside the constructor
constructor(props) {
super(props);
this.state= {
text: props.initial
}
}
the code above should work
However, this is a better way of structuring a component like TextArea and it should also solve your problem of props.initial not having a value on runtime
First, you need to prepare the handleChange method in the parent component
class ParentComponent extends Component {
constructor(props) {
super(props)
this.state = {
myTextArea: ''
}
this.handleChange = this.handleChange.bind(this)
}
handleChange (e) {
this.setState({myTextArea: e.target.value})
}
render () {
return (
<TextArea
value={myTextArea}
onChange={this.handleChange}
/>
)
}
}
and on the text area component, you refer to onchange method passed through the props when defining the onchange method of your textarea.
<textarea
value={this.props.value}
placeholder="Something"
onChange={this.props.handleChange}
/>
the benefit of this approach is that one, the one that calls the textarea will always have an updated value, and two, this child element doesnt need to have a state. it makes managing a large react app easier and its the correct mind set to have once you start trying to implement Redux or similar frameworks to handle your state for you

Categories