React form handeling? - reactjs

When using forms or input tags in react I use useState for the value of the form.
const [value,setvalue]=useState("");
onInput(e)=>{setvalue(e.target.value)};
But with this each time the user fills the form the component gets rerendered. Is there any better way to do that?

if you are using a form you can use onSubmit
<form onSubmit={this.handleSubmit}>
<input type="text" name="input1" />
<button type="submit">Submit</button>
</form>
and in handleSubmit function:
handleSubmit(event) {
event.preventDefault();
var input1 = event.currentTarget.input1.value;
// Do the rest
}

Related

how to use useRef from outside of the component

what i am trying to achieve that i made a react custom component for an input field looks like this in a seperate folder with name input.js
export function Input({id,type,label,name}) {
return (
<div className="form_container">
<input type={type} id={id} className="form__input" name={name} autoComplete="" placeholder=" " />
<label htmlFor="email" className="form__label">{label}</label>
</div>
)
}
and i used it inside my contact.js file which i want to use multiple times like this
const fname = useRef(null);
<form action="" onSubmit={sendEmail}>
<Input ref={fname} id='inputName' type="text" name="fname" label="Name" />
<button type='submit'> Submit </button>
</form>
const sendEmail = (e) => {
e.preventDefault();
console.log(fname.current.value);
}
but i am getting this error while trying to refresh the page and i cannot access the input to get the value of it
react-dom.development.js:67 Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
only the old class components can be given refs natively.
use need useImperativeHandle hook combined with forwardRef
https://reactjs.org/docs/hooks-reference.html#useimperativehandle

How to access state from components to the parent component

I have a form in which all input, select tags are separate components and each component but the submit button is in the form it self like-
<form>
<InputComp1 />
<InputComp2 />
<Select1 />
<Select2 />
<button type='submit' value='Register'/>
</form>
So how do I collect all state from various components and when user clicks on the submit the values get submitted.?
Is this approach while dealing with forms right? or should I manage state of all tags in the same component?
Manage the state of all inputs/selects in this component. You can pass values and handler functions to the inputs using props.
There is no "right" approach, the answer depends on the context.
You can have form as a controlled component, where you manage the state of all tags (while passing callbacks down the tree) as you suggested and as mentioned in docs.
Or, you can have it as uncontrolled component, for example:
const Input = ({ name }) => {
return <input name={name} />;
};
const Component = () => {
return (
<>
<form
onSubmit={(e) => {
e.preventDefault();
const data = new FormData(e.target);
const entries = data.entries();
for (let entry of entries) {
console.log(entry);
}
}}
>
<Input name="username" />
<Input name="email" />
<input type="submit" value="Submit" />
</form>
</>
);
};
See controlled vs uncontrolled components.
Yes you should manage the state in the parent component itself and pass the onchange handler and value of that field as props inside the child components to update the value of the form fields.
Solution #1 would be "manage state react way". With this you should store state you need to share between components somewhere in their common ancestor. In your case it would be component that holds Form
Solution #2 applicable only if you use real form and form controls. Handle 'submit' event from the form and get all you need to submit from form data.
Solution #3 applicable only if you use some sort of "state manager". Follow instructions and best practices of the library you use.
In some cases you can mix and match that solutions. For example I still recommend to handle 'submit' event on form regardless of solution.
there is a concept of state lifting in react:
create a controlled form here and for every child, component pass a function to get the data from child components to parent one. by doing this you can submit all the values once.
here is the example
import React, {useState} from 'react';
const ChildInput = ({onChange, id}) => {
return(
<input
key={id}
type="text"
placeholder="enter name"
onChange={onChange}
/>
)
}
const Parent = () => {
const [name, setName] = useState('');
const onSubmit =(e)=>{
e.preventDefault();
// append your all data here just like child component
data = {name}
}
return(
<form onSubmit={onSubbmit}>
<ChildInput onChange={()=>setName(e.target.value)} id="name" />
<button type="submit" value="submit"/>
</form>
)}
for more information check this one: https://reactjs.org/docs/glossary.html#controlled-vs-uncontrolled-components

Get value from textarea input in event object

I have a form with a textarea where users can put comments, and then trigger a onClick (when the form is submitet via the button).However, I cant get the value of the input, for example if a user writes "test", I want it to get into the handleSubmit function.
My form
<form onSubmit={this.handleSubmit.bind(this)} method="POST">
<label>Skicka</label>
<textarea placeholder="Type in comments (allergis etc.)" name ="name" ref ="name"></textarea>
<button className="btn" type="submit">
Send
</button>
</form>
//my handler
public handleSubmit = event => {
event.preventDefault();
console.log(event.name.value)
}
You have to save the textarea value separately in the onChange method of the textarea like this (for class component):
<form onSubmit={this.handleSubmit.bind(this)}
method="POST"
>
<label>Skicka</label>
<textarea
onChange={this.setComments}
placeholder="Type in comments (allergis etc.)"
name="name"
value={this.state.comment}/>
<button className="btn" type="submit">
Send
</button>
</form>
// The save function
const setComments = e => this.setState({comment: e.target.value});
This will save the textarea input in your local state and you can access it in your submit function with this.state.comment.
Hope this helps. Happy coding.
As you are using Uncontrolled Component. You can make use of ref to get value.
handleSubmit = (event) => {
event.preventDefault();
console.log(this.refs.name.value)
}
Demo
Note: In React you should never add method="POST" and action attribute's on form.
Don't add public keyword to your function (if you are not using typescript).
Better approach to work with form values, is Controlled Component
You can fix it by changing the handleSubmit method. Check below updated method.
public handleSubmit = event => {
event.preventDefault();
console.log(event.target.name.value)
}
But if you are work with React application then update the state variable via onChange event.

How access specific DOM in React js

I'm trying to get input tags' HTML inner values when submitting a form.
private handleSubmit = (event: any) => {
event.preventDefault();
console.log(event.currentTarget);
};
When the submit the form, it calls the function handleSubmit and it console logs the following.
Under the form tag, the first div has username value and the second div has password value. I would like to acess the two values. I think I should use DOM to do that, but can't be sure if I'm going for the right direction cuz I found some postings saying using DOM is not recommended.
Can anyone explain how I can acheive this?
Ideally you should update your state as the user enters information, and then access the data from the state. This would also allow you to run any validation on the data prior to it going into the state if you'd like.
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
username: null,
password: null
}
this.submitForm = this.submitForm.bind(this);
this.updateState = this.updateState.bind(this);
}
updateState (e) {
this.setState({[e.target.name]: e.target.value})
}
submitForm (e) {
e.preventDefault();
console.log(this.state);
}
render() {
return (
<div className="App">
<form onSubmit={this.submitForm}>
<input type="text" name="username" placeholder="username" onChange={this.updateState} /><br />
<input type="password" name="password" placeholder="password" onChange={this.updateState} /><br />
<button type="submit">Submit</button>
</form>
</div>
);
}
}
export default App;
The above code does the following:
Stores default values for username and password. While this isn't required, it makes the code more readable
binds this to functions that need to access state
Uses an updateState() function that is called onChange of the inputs
updateState uses the name attribute of the input as the key for the state
You could customize the updateState() function to do some validation, before saving to state if you'd like.
Excessive Rendering
ReactJS is pretty smart to no re-render the REAL DOM if your render() method doesn't actually rely on the state values that were updated; however, if you'd like to prevent ReactJS from even creating the Virtual DOM and comparing, you could utilize the shouldComponentUpdate() lifecycle hook.
In the particular example above, since render doesn't rely on ANYTHING in state, you could simply add the following method:
shouldComponentUpdate(prevState, nextState) {
return false;
}
That will prevent the render method from EVER re-rendering, which is most likely not going to work in a normal component, thus you could do something like this instead, only re-rendering on values you care about.
shouldComponentUpdate(prevState, nextState) {
if (nextState.email !== prevState.email) {
return true
}
return false;
}
Demo
https://repl.it/#AnonymousSB/SO53689072
If you want to use the DOM, once you have the form element (event.currentTarget in your case), you can use the .elements property to access a list of child inputs and buttons.
Alternatively, you can use React refs to keep track of the underlying HTML element when it's rendered.
render() {
return ... <input ref={(e) => this._name = e; } ....> ... ;
}
handleSubmit(e) {
var name = this._name ? this._name.value : '';
....
}
This can achieve what you want to
class Login extends Component{
state={
username:"",
password:""
}
onChange = (event)=>{
event.preventDefault()
this.setState({
[event.target.name]: event.target.value})
}
onSubmit = (event)=>{
event.preventDefault()
// submit whatever is in state from here
console.log(this.state)
}
render(){
return(<div>
<form onSubmit={handleSubmit}>
<input type="text" name="username" onChange={this.onChange} /><br />
<input type="password" name="password" onChange={this.onChange} /><br />
<button type="submit">Submit</button>
</form>
</div>)
}
}

I cannot clear input on submitting form

I am using reactJs coupled with redux-form.
And also using the semantic ui react library
When i want to submit my form, i don't want my page to be refreshed. Instead i want to reset my form after the submission.
Unfortunately, i can't clear my input whereas i set the state to void the value.
/** Form component **/
<Form onSubmit={handleSubmit(this.handleSubmitAction)}>
<Field name="input" component={renderTitleInput} onChangeAction={this.handleInputChange} defaultValue={this.state.input} />
<input type="submit" name="submit" />
</Form>
/** HandleSubmit function **/
handleSubmitAction = (e) => {
this.setState({input:''})
}
The field remain filled after submitting the form.
Any suggestion ? thanks
What you created is an uncontrolled component, which means that update must be handled through the DOM. To do that you need to add the refattribute to get access to the DOM element in the form submit callback. Here is the changes you need to make.
<Form onSubmit={handleSubmit(this.handleSubmitAction)}>
<Field name="input" component={renderTitleInput} onChangeAction={this.handleInputChange} defaultValue={this.state.input} ref={(input) => this.input = input} />
<input type="submit" name="submit" />
</Form>
/** HandleSubmit function **/
handleSubmitAction = (e) => {
// This can be used when using controlled component.
//this.setState({input:''})
this.input.val = '';
}
But maybe what you want is to handle it as controlled component.
I had a similar issue and I want to clear input after submit button is clicked & use the functional component. here is an example of how I reset the value of input field after submitting.
Set value of the input to state value & when state value is reset input field get reset and the field is empty.
const [cancelInput, setCancelInput] = useState('');
const inputChange = (event, data) => {
// console.log(data)
setCancelInput(data.value)
}
const handleClick = (e) => {
setCancelInput(e.target.value)
}
<Input onChange={inputChange} placeholder='Type cancel here' value={cancelInput}/>
<Button color='red' onClick={handleClick} disabled={cancelInput !== 'cancel'} loading={loading} >Cancel</Button>

Resources