Handling form submissions without handling changes? - reactjs

I'm new to front-end development so please forgive me if this is an ignorant question. I'm using ReactJS to build a simple SPA with several form components. In the official React docs and other tutorials I've read online, it seems like to be able to handle a form submission, I also have to handle form changes, i.e. update the component state with each keystroke, like so:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
This seems wasteful to me since I'm only interested in the final form value that's been submitted. Is there a way to access the value of the submitted form in the submission event handler so that I can only update the state once and eliminate the need to handle any non-submission change?

It may seem wasteful, but that is exactly the React way of doing it:
https://reactjs.org/docs/forms.html
Any way of trying to get around this would be more hacky than efficient. This may help keep you from duplicating code while trying to track all your input values:
When you need to handle multiple controlled input elements, you can add a name attribute to each element and let the handler function choose what to do based on the value of event.target.name.
This way you only need one 'handleChange' method.

A controlled component is not really necessary in this case. Update the input component to:
<input type="text" name="username" required/>
Now handle only the onSubmit. The value can be retrieved at:
event.target.username.value
Add the attribute "required" to the input tag for automatic validation.

Related

Antd form doesn't seem to process line breaks?

Curious if someone has come across this issue - I'm using a form to submit what are essentially comments on a blog, but I switched from a basic React form to an antd form. All is well, but the antd form doesn't seem to process line breaks in the text on input. How do I preserve the line break info in text input that I had with the old form?
Here's code for the old react form:
class Submit extends Component {
constructor(props) {
super(props);
this.state = {
value: "(Tell a story...)",
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleSubmit(event) {
alert("Your story reads: " + this.state.value);
event.preventDefault();
let itemLore = this.state.value;
console.log("state value test:" + itemLore);
submitLore(itemLore);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<textarea value={this.state.value} onChange={this.handleChange} />
<input type="submit" value="Submit ItemLore" />
</form>
);
}
}
The above code handles line breaks correctly, but in using the antd form (for formatting reasons) I'm noticing that line breaks aren't included at all.
Because I'm just importing an antd form, the code below doesn't show of what's under the hood. Any suggestions of what changes I should be making to the antd form to get my line breaks back?
<Form.Item name="itemLore">
<Input.TextArea placeholder="(Tell a story...)"></Input.TextArea>
</Form.Item>

How to get data from a form in React

I have a form on my React site and I am trying to get the data that a user enters. I have followed the documentation here, and a similar Stack Overflow post here, and when I press the submit button, I get the alert message. However, it doesn't let me type anything in the input field.
My code:
class Search extends Component {
constructor(props) {
super(props);
this.state = { value: "" };
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<div className="Search">
<form className="searchBox" onSubmit={this.handleSubmit}>
<input type="text" value={this.state.value}/>
<input type="submit" value="Go" />
</form>
</div>
);
}
}
If you are using default form setup of react then you need to use onChange handler for every input field and also maintain states for those fields too but in my opinion you should use Formik as it provides way more functionalities than default react form setup and also form validations.
But to give you an answer of your question -
Use onChange handler for your input field and during submission access those input handler states.

Difference between React controlled component and uncontrolled component

I am new to react and while learning I come across this example of controlled component.
function App() {
let [fName, setFName]=useState('');
return (
<div className="container">
<h1>Hello {fName }</h1>
<input name ='fname' value={fName} onChange={(e)=> setFName(e.target.value)} type="text" placeholder="What's your first name?" />
</div>
);
}
just adding value={fName} makes is controlled . I don't actually understand what does it mean by controlled component and uncontrolled. Can you explain it from beginner prospective.
An uncontrolled component means that you will let the component itself manage the value. It's own internal mechanism will keep track of it.
Now when you add the value property to the input component, you will start to "control" the component yourself. The value you put into that property, will be the value that will be displayed.
You can literally control the value yourself, by just passing it in as is, or by changing the value before passing it in.
Controlled Components
These components have what is called a callback function that is triggered each time we enter something new in the form element.
Triggering the function will typically store or update what we type in the same React component that displays the form element that was used
Most widespread use it with forms
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Unontrolled Components
These components such as <input> typically maintain their own state and update it based on user input.
In other words, they will accept what we type and have the responsibility of remembering it, and in order to retrieve the values they remembered, you have to get it when you need it.
The latter usually happens during form submission. They can be classified under uncontrolled components.
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.input = React.createRef();
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Here, Reactjs documentation provided explanation.
A Controlled Component is one that takes its current value through props and notifies changes through callbacks like onChange. A parent component "controls" it by handling the callback and managing its own state and passing the new values as props to the controlled component. You could also call this a dumb component/stateless component.
An Uncontrolled Component is one that stores its own state internally, and you query the DOM using a ref to find its current value when you need it. This is a bit more like traditional HTML.
React form components support both controlled and uncontrolled usage:
// Uncontrolled:
<input type="text" defaultValue="hey" ref={inputRef} />
// Controlled:
<input type="text" value={this.state.value} onChange={onHandleChange} />

Posting changed form field values in React

I have a form which is passed a value through props, and submits to an endpoint to update a users information. However, I'm unable to send an edited value of the text input field, as its state needs to be managed and updated when a user changes its value, but having trouble setting/updating the state of the input when the user changes the value, allowing a different value to be posted.
class DisplayNameModal extends React.Component {
constructor (props){
super(props)
this.state = {
displayName: this.props.displayName,
email: this.props.email.split('#')[0]
}
this.updateDisplayName = this.updateDisplayName.bind(this)
}
updateDisplayName () {
const email = this.props.email
const displayName = this.state.displayName
const user = {
email,
displayName
}
superagent
.put('/api/user')
.send({user})
.then(this.closeModal)
}
handleDisplayNameChange = e => this.setState({ displayName: e.target.value })
render (props) {
const {contentStrings} = this.props.config
return (
<div>
{ !this.props.displayNameModalActive &&
<div className='display-name-container' style={{ backgroundImage: `url(${this.props.bgImgUrl})` }}>
<div className='display-name-content'>
<h2 className='heading'>{contentStrings.displayNameModal.heading}</h2>
<p>{contentStrings.displayNameModal.subHeading}</p>
<input type="text"
defaultValue={this.state.displayName}
onChange={this.handleDisplayNameChange}
minLength="3"
maxLength="15"/>
<button
type='submit'
onClick={this.updateDisplayName}
className='btn btn--primary btn--md'>
<span>{contentStrings.displayNameModal.button}</span>
</button>
<p className='cancel'>{contentStrings.displayNameModal.cancel}</p>
</div>
</div>
}
</div>
)
}
}
export default DisplayNameModal
I think you need an onChange on your <input /> to update displayName on component state.
handleDisplayNameChange = e => this.setState({ displayName: e.target.value });
<input type="text"
value={this.state.displayName}
minLength="3"
maxLength="15"
onChange={this.handleDisplayNameChange}
/>
and instead of defaultValue, use value to make it a controlled input
So then in your updateDisplayName, you would use this.state.displayName instead of this.props.displayName. The prop is just being used to set the initial component state value, allowing it to be edited.
onChange event, call a method, and inside it use this.setState to set the changed text to state as you type in Input box.
On submit, use the updated State value to pass it to the API.
In this way, you can maintain updated value in local state.
You are using uncontrolled input element, ie React doesnt know, wats going on with ur input element.
In order, for React to know about it, it hould be made controlled component.
This can be done by connecting it value to the the state of the component,
Check example below.
This means, that at any time, react will know, wat is the value of the input element
Controlled Components
In HTML, form elements such as , , and typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated with setState().
We can combine the two by making the React state be the “single source of truth”. Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a “controlled component”.
For example, if we want to make the previous example log the name when it is submitted, we can write the form as a controlled component:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Since the value attribute is set on our form element, the displayed value will always be this.state.value, making the React state the source of truth. Since handleChange runs on every keystroke to update the React state, the displayed value will update as the user types.
With a controlled component, every state mutation will have an associated handler function. This makes it straightforward to modify or validate user input. For example, if we wanted to enforce that names are written with all uppercase letters, we could write handleChange as:
handleChange(event) {
this.setState({value: event.target.value.toUpperCase()});
}

questions about react controlled text field?

You can see below sample code, it's a typical controlled field.
export default class NameForm extends Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
return (
<form>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
I can understand that if I type any text in the field, the value will be reflected into the text field due to the setState function and the value props of the input.
But if I changed the input to below. I removed the value props.
<input type="text" onChange={this.handleChange} />
Currently, If I typed any value in the field, the value will be still there, but as per my knowledge of React, the input will be rendered after the setState, but the props value is not set, the input will be cleared in my opinion, Could you please explain it in detail for me?
I think you miss the important point here. After setState is called the component render will be called - but this will not recreate the input component from scratch. Internally react will check and apply only changes that has happened to the actual DOM.
In your case no differences to the input were made - therefore it will stay as it is.
This process is called reconciliation and you can read more about it here.
Setting value on an input element makes it a controlled input. Controlled inputs always show the value provided in their prop. For example if you have this input:
<input value='constant' onChange={({target: {value}}) => this.setState({value})}/>
User can't change its value. but if you don't provide value prop for your input it's not a controlled value and it shows the value user enters in. This same thing is true for checkboxes, radio buttons, etc.
So in your case it updates based on user input because it's not a controlled component (because you didn't provide value for it.)
If you want to set initial value for a component but keep it uncontrolled (user can change the value of component) you can set the initial value with defaultValue prop.
You can read more here:
https://facebook.github.io/react/docs/forms.html
You shouldn't be setting the value, just the defaultValue, like this
<input type="text" defaultValue={this.state.value}
The handleChange will then make sure the state is updated

Resources