Error while updating a prefilled input field in React - javascript

I prefilled the input fields in my edit-file with data from my database. I can change the values, but when I press my update button, I get the following error:
Warning: A component is changing an uncontrolled input to be
controlled. This is likely caused by the value changing from undefined
to a defined value, which should not happen. Decide between using a
controlled or uncontrolled input element for the lifetime of the
component.
Here is my code:
const savedData = {
img:"",
ressort:"",
theme:"",
title:"",
content:"",
};
const [data, setData] = useState(savedData);
const dispatch = useDispatch();
const {id} = useParams();
useEffect(()=>{
if(isError){
window.alert(message);
}
dispatch(getMainNews(id));
return ()=>{
dispatch(reset());
}
},[dispatch, isError, id, message]);
//Bring Data into savedData
useEffect(()=>{
if(mainnews){
setData({...mainnews})
}
return ()=>{
dispatch(reset());
}
},[mainnews, dispatch]);
//updateData
const updateData = (e)=>{
const {value, name} = e.target;
setData({...data, [name]: value})
// setData((prevState)=>({
// ...prevState,
// [e.target.name]: e.target.value,
// }))
}
const {img, ressort, theme, title, content} = data;
const onSubmit = (e)=>{
e.preventDefault();
const mainnewsData = {
img,
ressort,
theme,
title,
content,
}
dispatch(updateMainNews(mainnewsData))
}
In the return:
<MainNewsForm encType="multipart/form-data" onSubmit={onSubmit}>
<Formgroup>
<Label htmlFor="img">Image</Label>
<Input type="text" name="img" id="img" value={img} onChange={updateData}/>
</Formgroup>
<Formgroup>
<Label htmlFor="ressort">Ressort</Label>
<Input type="text" name="ressort" id="ressort" value={ressort} onChange={updateData}/>
</Formgroup>
<Formgroup>
<Label htmlFor="theme">Theme</Label>
<Input type="text" name="theme" id="theme" value={theme} onChange={updateData}/>
</Formgroup>
<Formgroup>
<Label htmlFor="title">Title</Label>
<Input type="text" name="title" id="title" value={title} onChange={updateData}/>
</Formgroup>
<Formgroup>
<Label htmlFor="content">Content</Label>
<Textarea type="text" name="content" id="content" value={content} onChange={updateData}></Textarea>
</Formgroup>
<ButtonHolder>
<UpdateButton type="submit">Update</UpdateButton>
</ButtonHolder>
</MainNewsForm>

Related

How do I not allow submission for empty fields from a child component? More explanation below

I have this sample codesandbox I made, though, in my original one there were already a lot of values. I only recreated the problem that I had.
Codesandbox: https://codesandbox.io/s/youthful-firefly-40mig3?file=/src/App.js
I have this in my App.js where I define some of my needed values and then pass it to 2 other components.
<div className="App">
{/* some codes here */}
<h1>App page</h1>
Initial Amount: 1000
<br />
Total Amount: {totalAmount}
<br />
----------------------------------------------------------
<h6>Passing the total amount and the second input here</h6>
<Second input2={input2} setInput2={setInput2} />
----------------------------------------------------------
<h6>Third here</h6>
<Third totalAmount={totalAmount} />
</div>
I have this Second.js where I compute the totalAmount. This is the problem that I encountered. The required is not being recognized here. I just wanted to stop the user from submitting the form if this field is empty. Are there other ways where it would not submit if a certain field is empty or just leave the input field to 1 if it is empty?
const Second = ({ input2, setInput2 }) => {
return (
<div>
Second here
<form>
<input
fullWidth
value={input2}
onChange={(e) => setInput2(e.target.value)}
required
/>
</form>
</div>
);
};
export default Second;
This is the Third.js where I passed down the totalAmount and added more values such as the name and age. In here the name and age are being recognized. This is also where I submit everything here.
const Third = ({ totalAmount }) => {
const [name, setName] = useState("");
const [age, setAge] = useState(0);
const handleSubmit = (e) => {
e.preventDefault();
try {
console.log(name, age, totalAmount);
} catch (err) {
console.log(err);
}
};
return (
<div>
Third here
<form onSubmit={handleSubmit}>
<label>Name</label>
<input
fullWidth
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
<br /> <br />
<label>Age</label>
<input
fullWidth
value={age}
onChange={(e) => setAge(e.target.value)}
required
/>
<br /> <br />
<button type="submit">submit</button>
</form>
</div>
);
};
export default Third;
You can pass the input2 as a prop to Third.js and there you can check if input2 doesn't exist then don't submit the values.
In the App.js pass input2 to the Third component.
<Third totalAmount={totalAmount} input2={input2} />
Then in Third.js check if the input2 value exists.
const Third = ({ totalAmount, input2 }) => {
const [name, setName] = useState("");
const [age, setAge] = useState(0);
const handleSubmit = (e) => {
e.preventDefault();
if (input2) {
try {
console.log(name, age, totalAmount);
} catch (err) {
console.log(err);
}
}else {
alert('Please enter the second value');
}
}
}

Saved data values not saving correctly on react front end

Good afternoon,
For my end project, I created a reminder app where you can add a TaskName, TaskDetails, Date, and Time.
My back end is created with java spring boot and I'm using a MySQL server.
When you add some data into the app it saves it to the database but everything is Null instead of text.
I have looked everywhere for a solution but could not find any.
My guess is I need to convert the text from React to java but this did not work either.
If someone could point me in the right direction I would be grateful!
import {useState} from "react";
const AddTask = ({onAdd}) => {
const [text, setText] = useState('')
const [details, setDetails] = useState('')
const [day, setDay] = useState('')
const [time, setTime] = useState('')
const [reminder, setReminder] = useState(false)
const onSubmit = (e) => {e.preventDefault()
if (!text){
alert('Please add a task')
return
}
onAdd({text, day, reminder})
setText('')
setDetails('')
setDay(Date)
setTime(Date)
setReminder(false)
}
return(
<form className='add-form' onSubmit={onSubmit}>
<div className='form-control'>
<label>Task</label>
<input type='text' placeholder='Add Task'
value={text} onChange={(e) => setText(e.target.value)}/>
</div>
<div className='form-control'>
<label>Task Details</label>
<input type='text' placeholder='Add Task Details'
value={details} onChange={(e) => setDetails(e.target.value)}/>
</div>
<div className='form-control'>
<label>Day</label>
<input type='date' placeholder='Add Day'
value={day} onChange={(e) => setDay(e.target.value)}/>
</div> <div className='form-control'>
<label>Time</label>
<input type='time' placeholder='Add Time'
value={time} onChange={(e) => setTime(e.target.value)}/>
</div>
<div className='form-control form-control-check'>
<label>Set Reminder</label>
<input type='checkbox'
checked={reminder}
value={reminder} onChange={(e) => setReminder(e.currentTarget.checked)}/>
</div>
<input type='Submit' value='save Task'
className='btn btn-block' />
</form>
Thank you in advance!
Here are some pictures:
[
Instead of creating a state for each element of your form, you can create a single object and change it's values when you need. Here is my approach.
// Create a empty object to use on hook
const initialFormData = Object.freeze({
task: '',
details: ''
})
const [formData, updateFormData] = useState(initialFormData)
On your form inputs change your onChange to update state form data:
<TextField
type="text"
name="task"
label="Task..."
onChange={e => updateFormData({ ...formData, task: e.target.value })}
/>
And on your submit function you can get values by acessing state objects:
const onSubmit = e -> {
e.preventDefault()
console.log(formData.task)
}

Why event target not passing through multiple react functions?

So I am trying to make a textfield component in React that is highly reusable but whenever I try to access event.target.name or event.target.value I get empty data.
Is there any way to get this code to work?
function LoginForm() {
const [form, setValues] = useState({
username: "",
password: ""
});
const printValues = e => {
e.preventDefault();
console.log(form.username, form.password);
};
const updateField = e => {
setValues({
...form,
[e.target.name]: e.target.value
});
};
const TextField = props => {
return(
<label>
React Component:
<input
value={props.value}
name='react'
onChange={e => props.change(e)}
/>
</label>
)
}
return (
<form onSubmit={printValues}>
<TextField
value={form.username}
name='username'
change={updateField}
/>
<br />
<TextField
value={form.password}
name='password'
change={updateField}
/>
<br />
<button>Submit</button>
</form>
);
}
This code is an example that I have gotten to work. Why does this code work but not the code above?
function LoginForm() {
const [form, setValues] = useState({
username: "",
password: ""
});
const printValues = e => {
e.preventDefault();
console.log(form.username, form.password);
};
const updateField = e => {
setValues({
...form,
[e.target.name]: e.target.value
});
};
return (
<form onSubmit={printValues}>
<label>
Username:
<input
value={form.username}
name="username"
onChange={updateField}
/>
</label>
<br />
<label>
Password:
<input
value={form.password}
name="password"
type="password"
onChange={updateField}
/>
</label>
<br />
<button>Submit</button>
</form>
);
}
your child component has it's name prop hardcoded name='react' and that's because your [e.target.name]: e.targe.value statement is not working, use name={props.name} instead and it would solve the problem.
const TextField = props => {
return(
<label>
React Component:
<input
value={props.value}
name={props.name}
onChange={e => props.change(e)}
/>
</label>
)
}
The first code you show has a prop change instead of the onChange event listener in the TextField component.
I was looking here https://material-ui.com/es/components/text-fields/ because I never used material-ui, and in the example they still use the regular onChange.
So try changing change for onChange, as it is the only difference between both code examples besides the use of the component.

React onChange not updating state

I am creating a simple login form and I am saving the users information to state as they type. However, the value does not register to state as expected.
Here is the user state
const [user, setUser] = useState({
firstName: '',
lastName: '',
email: ''
});
Here is the input component
export function Input({ id, placeholder, autoComplete, type, name, label, value, handleInputChange }) {
return (
<div className="form-input">
<label className="form-label" htmlFor={id}>{label}</label>
<input
placeholder={placeholder}
autoComplete={autoComplete}
id={id}
type={type}
name={name}
value={value}
onChange={handleInputChange}
/>
</div>
)
}
Here is the handleInputChange function that is passed into the input component
function handleInputChange(event) {
const { name, value } = event.target;
setUser({ ...user, [name]: value });
}
Here is how one of the input components is used in the parent component
<Input
id="first-name"
placeholder="Charlie"
autoComplete="given-name"
type="text"
name="firstName"
label="First Name"
value={user.firstName}
handleInputChange={handleInputChange}
/>
Here are some resources I've looked at thus far:
https://reactjs.org/docs/hooks-reference.html#usestate
onChange not updating React
https://daveceddia.com/usestate-hook-examples/
I'd suggest to create one state per input field:
export function Form({ addItem }) {
const [name, setName] = useState('');
return (
<form>
<Input
id="first-name"
placeholder="Charlie"
autoComplete="given-name"
type="text"
name="firstName"
label="First Name"
value={user.firstName}
handleInputChange={(event) => setName(event.target.value)}
/>
</form>
);
}

Reset form input values in React

I want create a function using with i can reset value in form inputs without submit. I tried create that function in App Component (resetFormFields) and pass it on props to Form Component. It's preety simply when I want to do this onSubmit (e.target.reset()) but I got stuck when I have to do it without submit, on a different element than the form. Can I do that without adding these values to state?
App:
class App extends Component {
state = {
people: [],
formMessages: [],
person: null
};
handleFormSubmit = e => {
e.preventDefault();
const form = e.target;
const name = form.elements["name"].value;
const username = form.elements["username"].value;
this.addPerson(name, email);
form.reset();
};
resetFormFields = () => {
return;
}
render() {
return (
<div className="App">
<Form formSubmit={this.handleFormSubmit}
reset={this.resetFormFields} />
</div>
);
}
Form:
const Form = props => (
<form className={classes.Form}
id="form"
onSubmit={props.formSubmit}>
<input autoFocus
id="name"
type="text"
defaultValue=""
placeholder="Name..."
/>
<input
id="email"
type="text"
defaultValue=""
placeholder="Email..."
/>
<Button
btnType="Submit"
form="form"
type='submit'>
Submit
</Button>
<label onClick={props.reset}>Reset fields</label>
</form> );
onHandleFormSubmit = (e) =>{
e.preventDefault();
e.target.reset();
}
You need to make your inputs controlled by passing the value you store in your state then you just have to reset the state values and your component value resets.
check this sample below
handleInputChange = (e) => {
let { name, value } = e.target;
this.setState({
...this.state,
inputs: {
[name]: value
}
});
}
your component will now look like
<input name='fullName' value={this.state.inputs.fullName} onChange={this.handleInputChange} />
Your reset function will just clear the state and your input field will be empty since it's controlled via state
resetInputFields = () => {
this.setState({ inputs: {} })
}
you should give set your input values based on component state, then just update the component state
class App extends Component {
state = {
people: [],
formMessages: [],
person: null,
name: "",
email: "",
};
updateState = (newState) => {
this.setState(newState);
}
handleFormSubmit = e => {
e.preventDefault();
this.addPerson(this.state.name, this.state.email);
form.reset();
};
resetFormFields = () => {
this.setState({name:"", email: ""});
}
render() {
return (
<div className="App">
<Form formSubmit={this.handleFormSubmit} updateState={this.updateState}
reset={this.resetFormFields} email={this.state.email} name={this.state.name} />
</div>
);
}
and then
const Form = props => (
<form className={classes.Form}
id="form"
onSubmit={props.formSubmit}>
<input autoFocus
id="name"
type="text"
defaultValue=""
value={this.props.name}
onChange={(e) => this.props.updateState({name: e.target.value})}
placeholder="Name..."
/>
<input
id="email"
type="text"
defaultValue=""
value={this.props.email}
onChange={(e) => this.props.updateState({email: e.target.value})}
placeholder="Email..."
/>
<Button
btnType="Submit"
form="form"
type='submit'>
Submit
</Button>
<label onClick={props.reset}>Reset fields</label>
</form> );

Categories