Edit Form React JS - reactjs

I´m making an edit form with React js. I have multiple components in the form. In one of the son components, I pass all the changes that I`ve done to a hook in the main component to do the changes in firebase.
Father Component
const [changes, setChanges] = useState({});
const updateGenData = (genData) => {
setChanges(genData);
}
Son Component(I take all the info from the father, via props)
const UpdateProfileGenData = (props) => {
const [values, setValues] = useState({});
const [changes, setChanges] = useState({});
useEffect(() => {
setValues(props);
},[props]);
const {field1, field2, field3} = values;
useEffect(() => {
props.updateGenData(changes);
},[changes]);
const handleChange= e => {
setValues({
...values,
[e.target.name]: e.target.value
});
setChanges({
...changes,
[e.target.name]: e.target.value
})
}
return (
<input type="text" name="field1" value={field1} onChange={handleChange}/>
<input type="text" name="field2" value={field2} onChange={handleChange}/>
<input type="text" name="field3" value={field3} onChange={handleChange}/>
);
}
export default UpdateProfileGenData;
When I pass the values ​​from the child component to the parent it doesn't allow me to edit the child form . I can´t change any field.
Any suggestions??
Regards

Why do you use useEffect so often? The problem may be that you often use useEffect and somewhere you overwrite the data correctly.
Can be made easier:
Father Component
const [changes, setChanges] = useState({});
const updateGenData = (genData) => setChanges({...changes, ...genData});
Son Component
const UpdateProfileGenData = ({field1, field2, field3, updateGenData}) => {
const handleChange= e => updateGenData({
[e.target.name]: e.target.value,
});
return (
<input type="text" name="field1" value={field1} onChange={handleChange}/>
<input type="text" name="field2" value={field2} onChange={handleChange}/>
<input type="text" name="field3" value={field3} onChange={handleChange}/>
);
}
export default UpdateProfileGenData;

Related

Unable to store data in useState

[Here is the view
So I have the following output.
I am unable to store the data from this form to the Array and an object.
Every time there is a change in children field there is another form that has to be stored.
I have to do this using and unique ID for each of them.
const CreateForm = () => {
const [isDisabled, setIsDisabled] = useState(false);
let [applicant, setApplicant] = useState([]);
const handleChildren = (e) => {
const udatedApplicant = { ...applicant };
udatedApplicant.childrens = e.target.value;
setApplicant({ ...udatedApplicant });
if (applicant.childrens!==0){
udatedApplicant.childrens= e.target.childrens=0;
}
};
const handleRadio = (e) => {
const udatedApplicant = { ...applicant };
udatedApplicant.maritalStatus = e.target.value;
setApplicant({ ...udatedApplicant });
};
// const finalForm = setApplicant(...applicant)
return (
<div>
<div>
<input name="firstName" placeholder="firstName" />
<input name="lastName" placeholder="lastName" />
<input type="email" name="Email" placeholder="Email" />
<div>
<label>
<input type="radio" name="Gender" value="Male" />
Male
</label>
I am able to handle all the onChanges fields but unable to store this using map in the useState applicant.
I tried it using the index, but after I store the first applicant, when I change the field married or children, I got a blank page.
Can someone help me handle this? I passed 2 hours on this and I'm still not able to store the data.
Im kinda new in React.
Any small tip would be appreciated.

Can't type in textarea when displayed

import React, { useState } from 'react'
const FormBox = () => {
const [name, setName] = useState("")
const [textArea, setTextArea] = useState('')
const handleSumbit = (e) =>{
e.preventDefault();
console.log(name)
}
return (
<form onSubmit={handleSumbit}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<textarea value={textArea} onChange={handleSumbit}></textarea>
<input type="submit" />
</form>
)
}
When the text box is displayed I cannot type in it.
What am I doing wrong...?
import React, { useState } from 'react'
const FormBox = () => {
const [name, setName] = useState('')
const [textArea, setTextArea] = useState('')
const handleSumbit = (e) =>{
e.preventDefault();
console.log(name)
}
return (
<form onSubmit={handleSumbit}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<textarea value={textArea} onChange={(e) => setTextArea(e.target.value)}></textarea>
<input type="submit" />
</form>
)
}
The textarea is a controlled input - if you are going to tie the value of the <textarea> to the textArea state variable, you need to update that state variable whenever the user changes the input.
Shouldn't the onChange={handleSumbit} of the textarea be
onChange={(e) => setTextArea(e.target.value)}
import React, { useState } from 'react'
const FormBox = () => {
const [name, setName] = useState("")
const [textArea, setTextArea] = useState('')
const handleSumbit = (e) =>{
e.preventDefault();
console.log(name)
}
return (
<form onSubmit={handleSumbit}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setTextArea(e.target.value)}
/>
</label>
<textarea value={textArea} onChange={handleSumbit}></textarea>
<input type="submit" />
</form>
)
}
Firstly
You implicitly set the value of your text area using the textArea variable which has an initial state of "" (an empty string).
React automatically refreshes the real DOM from the virtual DOM after every change in state. But the value of your textArea variable doesn't change with this event, so you have to update the state when a value is entered like this:
onChange={(e) => setTextArea(e.target.value)}
After reading your code, I guessed what you wanted to achieve is to prevent the submit button from submitting the form by default and instead logs the name on the console.
I believe this is the code you wanted to achieve:
import React, { useState } from 'react'
const FormBox = () => {
const [name, setName] = useState('')
const [textArea, setTextArea] = useState('')
const handleSumbit = (e) =>{
e.preventDefault();
console.log(name)
}
return (
<form onSubmit={handleSumbit}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<textarea value={textArea} onChange={(e) => setTextArea(e.target.value)}></textarea>
<input type="submit" />
</form>
)
You can't type here the event not written by you properly, so, you state textarea not updated yet. just needed to change one as a similar name textbox. just replace
<textarea value={textArea} onChange={handleSumbit}></textarea>
to
<textarea value={textArea} onChange={(e) => setTextArea(e.target.value)}></textarea>
Full code here edited,
import React, { useState } from 'react'
const FormBox = () => {
const [name, setName] = useState('')
const [textArea, setTextArea] = useState('')
const handleSumbit = (e) =>{
e.preventDefault();
// console here form data
}
return (
<form onSubmit={(e)=>handleSumbit(e)}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<textarea value={textArea} onChange={(e) => setTextArea(e.target.value)}></textarea>
<input type="submit" value="Submit now!" />
</form>
)
I Hope, work fine using this code
Thanks

Saving object in React.useState

I have a form in my react project, and I want the value of each field to be stored in the state.
instead of having multiple states for each field, how can I store the form value as an object in the state? and more importantly how can I access it? (with react hooks)
import React from 'react';
export const UserData = () => {
return(
<form>
<input type="text" placeholder="Name" />
<input type="email" placeholder="Email" />
<button>Confirm</button>
</form>
)
}
React Hooks allows you to define a JavaScript Object using useState. See
https://daveceddia.com/usestate-hook-examples/
function LoginForm() {
const [form, setState] = useState({
username: '',
password: ''
});
Update the form using the function :
const updateField = e => {
setState({
...form,
[e.target.name]: e.target.value
});
};
Call the function onSubmit of the button
<form onSubmit={updateField}>
<input type="text" placeholder="Name" />
<input type="email" placeholder="Email" />
<Button >Confirm</button>
</form>
You can use useState hook. Check this
const [state, setState] = useState({ name, email });
To set the state similar to setState in class based component:
setState({name: 'react', email: 'react'})
To access the state value:
import React, { useState } from 'react';
export const UserData = () => {
const [state, setState] = useState({ name, email });
return(
<form>
<input type="text" placeholder="Name" value={state.name} />
<input type="email" placeholder="Email" value={state.email} />
<button>Confirm</button>
</form>
)
}
You should create an initial state value if you want to store the form values as an object using useState, so you can rollback to the initial state after an error. Example,
const initialState = {
name: "",
email: ""
};
export const UserData = () => {
const [formState, setFormState] = useState(initialState);
const submitHandler = event => {
event.preventDefault();
console.log(formState);
};
return (
<form onSubmit={submitHandler}>
<input
type="text"
placeholder="Name"
value={formState.name}
onChange={e => {
setFormState({ ...formState, name: e.target.value });
}}
/>
<input
type="email"
placeholder="Email"
value={formState.email}
onChange={e => {
setFormState({ ...formState, email: e.target.value });
}}
/>
<button>Confirm</button>
</form>
);
};
Working demo in codesandbox.

React Input Warning: A component is changing a controlled input of type text to be uncontrolled

I am practicing REST API by using one Fake API site. For front-end, I am using React typescript and React router dom for routing. I successfully login the email and password by using Fake API's login and redirect to list users, where I fetched the data from Fake API and shows the user's name, image. I used the edit button, after clicking the button it will redirect to my Update components where it will populate the input field then I will update the data. My update components work fine as expected but in my console, I am getting a warning as soon as I type my input field.Here is the Error visualization
This is React Update components
import React, { useState, useEffect } from "react";
import axios from "axios";
const Update = props => {
const [state, setState] = useState({
first_name: "",
last_name: "",
email: ""
});
const [loading, setLoading] = useState(false);
useEffect(() => {
axios
.get("https://reqres.in/api/users/" + props.match.params.id)
.then(response => {
setState({
first_name: response.data.data.first_name,
last_name: response.data.data.last_name,
email: response.data.data.email
});
})
.catch(function(error) {
console.log(error);
});
}, [props.match.params.id]);
const onChangeFirstName = e => {
setState({
first_name: e.target.value
});
};
const onChangeLastName = e => {
setState({
last_name: e.target.value
});
};
const onChangeEmail = e => {
setState({
email: e.target.value
});
};
const onSubmit = e => {
e.preventDefault();
setLoading(true);
const obj = {
first_name: state.first_name,
last_name: state.last_name,
email: state.email
};
axios
.patch("https://reqres.in/api/users/" + props.match.params.id, obj)
.then(res => console.log(res.data));
setLoading(false);
props.history.push("/users");
};
return (
<div>
<form onSubmit={onSubmit}>
<div className="form-group">
<label>First Name: </label>
<input
type="text"
className="form-control"
value={state.first_name}
onChange={onChangeFirstName}
id="first_name"
/>
</div>
<div className="form-group">
<label>Last Name: </label>
<input
type="text"
className="form-control"
value={state.last_name}
onChange={onChangeLastName}
id="last_name"
/>
</div>
<div className="form-group">
<label>Email: </label>
<input
type="email"
className="form-control"
value={state.email}
onChange={onChangeEmail}
id="email"
/>
</div>
<div className="form-group">
<button
className="btn waves-effect blue lighten-1"
type="submit"
name="action"
disabled={loading}
>
{loading ? "loading..." : "save"}
</button>
</div>
</form>
</div>
);
};
export default Update;
With hooks, when you set the state of an object, you need to merge all the properties by yourself. In other words, if you update a property of an object with state updater, the remaining properties of the objects are not merged by themselves unlike this.setState in class components.
Modify your onChange to like this:
const onChangeFirstName = e => {
const val = e.target.value;
setState(prevState => ({
...prevState,
first_name: val
}));
};
See working demo
Also quick suggestion:
Instead of writing multiple onChanges, you can simplify and just use one.
Like this:
<input
type="text"
className="form-control"
value={state.first_name}
onChange={onChange}
id="first_name"
name="first_name" />
...
const onChange = e => {
const {name, value} = e.target;
setState(prevState => ({
...prevState,
[name]: value
}));
};

React TypeScript: Alternatives to UseRef in functional components

Is there another way of getting/setting the values from the dom that is less expensive than useRef()? Is useRef() to be used lightly as the docs suggest?
import React, { useRef, useEffect } from 'react';
const Join: React.FC = () => {
const fullName = useRef<HTMLInputElement>(null);
const email = useRef<HTMLInputElement>(null);
const password = useRef<HTMLInputElement>(null);
const myForm = useRef<HTMLFormElement>(null);
useEffect(() => {
if (myForm.current) myForm.current.reset();
if (fullName.current) fullName.current.focus();
}, []);
return (
<div>
<form ref={myForm}>
<input type='text' ref={fullName} />
<input type='text' ref={email} />
<input type='text' ref={password} />
</form>
</div>
)
}
When the component loads I want to clear the form and focus the
fullName input
You don't need refs for that
I want to clear the form
Make your inputs controlled
Declare an empty string as initial value
const Component = () =>{
const [state, setState] = useState({
email : '',
password : ''
})
const onChange = ({ target: { value, name } }) =>{
setState(prev => ({
...prev,
[name] : value
}))
}
const { email, password } = state
return(
<>
<input value={email} onChange={onChange} id='email'/>
<input value={password} onChange={onChange} id='password' />
</>
)
}
Automatically focus a given input
Just use autofocus for that
<input autofocus/>

Resources