Creating controlled input in react - javascript

I'm a newbie and learning React with FreeCodeCamp. On this challenge it says:
When you type in the input box, that text is processed by the
handleChange() method, set as the input property in the local state,
and rendered as the value in the input box on the page. The component
state is the single source of truth regarding the input data.
I wrote this solution:
class ControlledInput extends React.Component {
constructor(props) {
super(props);
this.state = {
input: ''
};
// Change code below this line
this.handleChange = this.handleChange.bind(this);
// Change code above this line
}
// Change code below this line
handleChange(event) {
this.setState({
input: event.target.value
})
}
// Change code above this line
render() {
return (
<div>
{ /* Change code below this line */}
<input value={this.state.input} onChange={this.handleChange()} />
{ /* Change code above this line */}
<h4>Controlled Input:</h4>
<p>{this.state.input}</p>
</div>
);
}
};
the console says:
“Build error, open your browser console to learn more.”
Where am I doing wrong? I cannot see my mistake..

The issue is related to how you assign the event handler to onChange.
onChange expects a callback function which will be fired when value of the input is changed. With onChange={this.handleChange()} in your post, you actually assigns undefined to onChange since handleChange function update the component state but it doesn't return anything.
Change it to onChange={this.handleChange} does what you expect it to work. When input is changed, this.handleChange will be called and event object will be passed in as parameter.
Hopefully that helps.

You're calling handleChange instead of passing its reference as the onChange prop.

You likely do not need to run your handleChange method in the onChange prop. So you would have this instead:
onChange={this.handleChange}

Related

React Updating Form Data

I have the following code:
import React from "react"
export default function Form() {
const [formData, setFormData] = React.useState(
{firstName: ""}
)
console.log(formData.comments)
function handleChange(event) {
setFormData(prevFormData => {
return {
...prevFormData,
[event.target.name]: event.target.value
}
})
}
return (
<form>
<input
type="text"
placeholder="First Name"
onChange={handleChange}
name="firstName"
value={formData.firstName}
/>
</form>
)
}
I'm trying to understand a few aspects of that that I'm not 100% on, and would appreciate if anyone could advise.
My understanding of the order of operations is as such:
The user types text into the input
onChange runs and triggers the handleChange callback
The handle change callback runs. This triggers the setter function which changes the state.
The form component is re-rendered due to the setter function being run.
I believe this is right, but it leads to a bit of confusion for me:
How is the console.log(formData.comments) being run each time a change is made? Does this happen when the form component is re-rendered? And if so, why doesn't const [formData, setFormData] = React.useState({firstName: ""}); also reset each time?
When my handleChange function runs, it triggers the callback which returns an identical object, except that we reassign one property, which is: [event.target.name] : event.target.value. If event.target.name and event.target.value are coming from what I pass to the input component, and value={formData.firstName}, how does my state ever update? Since I type a new character in the field, but the state isn't updated, and therefore value isn't updated, which means the old value should still be used.
Where can I view more information about event which is passed to my handler function?
Thanks to anyone who can help, I appreciate it!
The console statement runs because of the re-rendering of the component . Since formData is a state and uses useState api , it is not meant to re-initialize . Thats how react works since it compares the DOM to render new changes .
The setFormData is called and although it still contains the previous value since you are hardcoding the input value which is same as before but since the set method api of the useState is called the component is bound to re-render . Again this is how react works
You can always console log the event you passed inside the handler

React setState not firing in first time

i saw similar questions but can't get some solution.
i have some input when you paste some text to input i'm trying to set it to state and render this text. But when paste in first time state not change in second time when paste everything works.
I don't understand why it happen i already used some setTimeOut function too for it but not helped.
here is my code:
import React from "react";
import { render } from "react-dom";
class App extends React.Component {
constructor() {
super();
this.state = {
no: ""
};
}
pasteSomeText = e => {
this.setState({
no: e.target.value
});
};
render() {
return (
<div style={styles}>
{this.state.no}
<input onPaste={event => this.pasteSomeText(event)} />
</div>
);
}
}
render(<App />, document.getElementById("root"));
Here is codeSandBox example: https://codesandbox.io/s/1-react-hello-world-tvscf?fontsize=14
To get the data from the event, use e.clipboardData.getData('text'). See https://developer.mozilla.org/en-US/docs/Web/API/Element/paste_event
e.target.value gives you the value for the text field before it updates with the paste data, so you can cancel/modify the paste if you want.
pasteSomeText(e) {
this.setState({
no: e.clipboardData.getData('text')
});
};
Side note: with the call from the HTML, you don't need to use this arrow function (which uses more memory), see my example above
Basically the reason why you get empty state on firts onpaste call is that onpaste fires before the input's value is changed. So you get empty event.target.value and for all other calls you get previous value.
And if you still decide to keep going with onpaste you should keep in mind that you can get pasted value with event.clipboardData.getData('Text') but it can differ from what have been pasted in input because of different behavior of clipboardData for different input types.
https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types
So for work with clipboard data I will recommend to use DataTransfer module from https://www.npmjs.com/package/fbjs to get more consistant behavior in different systems and browsers.
Is a diferente kind of event you will need to get the clipboard data from the event and set it to the state
const value = e.clipboardData.getData('text')
use
onChange
instead of using
onPaste
Updated https://codesandbox.io/s/1-react-hello-world-h2jgv

Altering react form but input value not editable

I came from angularjs background, with 2 way binding I don't have to worry much, just declare a submit function, I can get the changed or unchanged value.
I'm stuck with react now. My input is not editable.
class HelloWorldComponent extends React.Component {
constructor(){
super();
this.handleChange = this.handleChange.bind(this)
}
render() {
const person = {"name":"james"};
return (
<input onChange={this.handleChange} type="text" placeholder="name" value={person.name} />
);
}
handleChange(e){
}
}
React.render(
<HelloWorldComponent />, document.getElementById('react_example')
);
http://jsbin.com/huluqifanu/1/edit?js,console,output
Also what to do next? should I set the api data to a state first?
If you do not want to use Controlled Components then you can use Uncontrolled Components.
Specifically, you can use the defaultValue prop instead of value on your input.
As to your second question, you will have to be more clear what you are asking or perhaps better to ask in a separate Q altogether.

Re-render does not occur when state changes

I have the following component...
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
register: false
}
}
handleClick(event)
{
console.log("link was clicked");
this.setState({register: true});
}
render(){
return (
<If condition={ this.state.register }>
<Then><Register /></Then>
<Else>{() =>
<Index event={this.handleClick} />
}</Else>
</If>
);
}
}
module.exports = App;
So my function handleClick is called whenever a link is clicked, this changes the state to true. However, the <IF> statement does not notice that state changed and so remains the same (only Index remains)
What I want is for <Register /> to be rendered whenever the link is clicked. So if the link is clicked, the state will change to true, and then the IF statement will catch this change and render the right component.
How can I do this? How can I get the IF statement to notice the change in state?
Not sure what <Index> is or what is it doing with event. If it just calls the function that is passed as props.event, the handleClick function is called with the wrong this reference and doesn't set the state for the correct component.
If you're using Babel with stage-2 preset or lower, you can use syntax to bind this:
class App ... {
...
handleClick = (event) => { ... }
...
}
Yes, it's an arrow function definiton, but directly inside class. It will bind the correct this reference so it can be passed around and it will have proper this reference when called.
Alternatively, you can use bind directly when passing the function, as event={this.handleClick.bind(this)}. But beware, this creates a new function every time it's called, so it might impact performance if it's called very often. It's advised that you do not use this approach and airbnb's eslint config will mark this as an error. A better approach would be to do one time binding inside the constructor, as this.handleClick= this.handleClick.bind(this).
If you wish to know more, this Medium post covers 2 more ways to bind and explains all 5 options.
you can do it by following code,
return (
{ this.state.register ? <Register /> : <Index event={this.handleClick.bind(this)} /> }
);

How to get the value of react component - AceEditor

I am facing the following issue while using AceEditor react component https://github.com/securingsincity/react-ace
I am using AceEditor as user input, after user enters code, he(she) presses the Run button. (see the picture) How do I extract the text that users enters from AceEditor component ?
It's not necessary to use onChange.
<AceEditor ref="aceEditor" />
this.refs.aceEditor.editor.getValue()
You need to subscribe to the onChange event (explained in the docs) and store the value passed into the callback somewhere, perhaps in the component's state if the Run button is on the same page. Then, when user clicks the button just retrieve it via this.state.xxx
With the latest React v16.12+ this.refName.current.editor.getValue() works to get string value which can be parsed using JSON.parse.
Ref should be instantiated as:
constructor(props) {
super(props);
this.refName = React.createRef();
}
and passed to AceEditor component:
<AceEditor
ref={this.refName}
/>
AceEditor provides an onChange event which you can use to retrieve the current content of the editor whenever the user changes it and then store the value in your own data store or your component's state.
This way, you are able to retrieve the value whenever you need it.
More about the editor's properties.
The readme also provides an example, demostrating its usage.
You need to bind this state to the onchange function in constructor of class.It worked for me.
constructor(props){
super(props);
this.state = {code:"code"};
this.onChange = this.onChange.bind(this);
}
onChange(newValue) {
this.state.code = newValue;
alert(this.state.code);
}
Ace Editor's Onchange is
onChange = {
this.onChange
}

Categories

Resources