Hello this is my first question here and I am just a beginner in Reactjs I need your explanation, please
the code is about Controlled Form wrote in-class component using "this.state".
I was trying time to turn it into a functional component using hooks with the same results
1- onSubmit render text on the screen
2- reset input into ""
the problem is no results going write and instead I got [object, Object] in the search
this is code
class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
submit: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
handleSubmit(event) {
event.preventDefault()
this.setState({
submit: this.state.input,
input:''
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input type='text'
value={this.state.input}
onChange={this.handleChange}
/>
<button type='submit'>Submit!</button>
</form>
<h1>{this.state.submit}</h1>
</div>
);
}
}
The code at codesandbox for fast access
please can you tell me how to solve it?
thank you
Here is what you need https://codesandbox.io/s/new-leftpad-1n0yy, you can compare your current MyForm with Form to understand the difference, but I suggest to check documentation deeper
Here is the answer by Artem Matiushenko he added the second component using useState, useCallback
now we can compare the two types for controlled form
import React, { useCallback, useState } from "react";
import "./styles.css";
class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {
input: "",
submit: "",
};
}
handleChange = (event) => {
this.setState({
input: event.target.value,
});
};
handleSubmit = (event) => {
event.preventDefault();
this.setState({
submit: this.state.input,
input: "",
});
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
type="text"
value={this.state.input}
onChange={this.handleChange}
/>
<button type="submit">Submit!</button>
</form>
<h1>{this.state.submit}</h1>
</div>
);
}
}
//using hooks------->
function Form() {
const [value, setValue] = useState("");
const [submitedValue, setSubmitedValue] = useState();
const handleOnChange = useCallback(({ target }) => {
setValue(target.value);
}, []);
const handleOnSubmit = useCallback(
(event) => {
event.preventDefault();
setSubmitedValue(value);
setValue("");
},
[value]
);
return (
<div>
<form onSubmit={handleOnSubmit}>
<input type="text" value={value} onChange={handleOnChange} />
<button type="submit">Submit!</button>
</form>
<h1>{submitedValue}</h1>
</div>
);
}
export default function App() {
return (
<div className="App">
<h1>Class Component Form</h1>
<h2>controlled form</h2>
<MyForm />
<Form />
</div>
);
}
here is mine after I understood how useSate works
const MyForm = () => {
const [input, setInput] = useState("");
const [submitText, setSubmitText] = useState("");
const handleChange = (event) => {setInput(event.target.value)};
const handleSubmit = (event) => {
event.preventDefault();
setSubmitText(input);
setInput("");
};
return (
<div>
<form onSubmit={handleSubmit}>
<input type="text" value={input} onChange={handleChange} />
<button type="submit">Submit!</button>
</form>
<h1>{submitText}</h1>
</div>
);
};
Related
Warning: A component is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.*
Following is my code:
import React, { useState, useReducer } from "react";
import Modal from "./Modal";
import { data } from "../../../data";
// reducer function
const reducer = (state, action) => {
console.log(state, action);
return state;
};
const defaultState = {
people: [],
isModalOpen: false,
modalContent: "",
};
const Index = () => {
const [name, setName] = useState("");
const [state, dispatch] = useReducer(reducer, defaultState);
const handleSubmit = (e) => {
e.preventDefault();
if (name) {
dispatch({ type: "TESTING" });
} else {
}
};
return (
<>
{state.isModalOpen && <Modal modalContent={state.modalContent} />}
<form className="form" onSubmit={handleSubmit}>
<div>
<input
type="text"
value={name}
onChange={(e) => setName(e.value)} //?
></input>
</div>
<button className="button" type="submit">
Add
</button>
</form>
{state.people.map((person) => {
return (
<div key={person.id}>
<h4>{person.name}</h4>
</div>
);
})}
</>
);
};
export default Index;
I have a form in a page, when the user inputs the name of a new student and clicks submit, I want the content of that component (the form) to be completely replaced by the submitted name. How can I achieve this (Replace the form with the list onsubmit)?
I have read that I can use conditional rendering to toggle components, but it's not really clear to me how i can apply it here.
StudentListResult.Jsx
import React, { useState } from "react";
import StudentForm from "./StudentForm";
import StudentList from "./StudentList";
const StudentListResult = () => {
const [newStudent, setNewStudent] = useState("");
const [students, setStudentsList] = useState([]);
return (
<div>
<div>
<StudentForm
newStudent={newStudent}
setNewStudent={setNewStudent}
students={students}
setStudentsList={setStudentsList}
/>
</div>
<div>
<StudentList students={students} setStudentsList={setStudentsList} />
</div>
</div>
);
};
export default StudentListResult;
StudentListForm
import React from "react";
import { v4 as uuidv4 } from "uuid";
const StudentListForm = ({
newStudent,
setNewStudent,
students,
setStudentsList,
}) => {
const addStudent = (event) => {
event.preventDefault();
setStudentsList([...students, { id: uuidv4(), name: newStudent }]);
setNewStudent("");
};
return (
<form onSubmit={addStudent}>
<div>
<input
value={newStudent}
type="text"
placeholder="Student Name"
onChange={(e) => setNewStudent(e.target.value)}
/>
</div>
<div>
<button>Submit</button>
</div>
</form>
);
};
export default StudentListForm;
StudentList.jsx
import React from "react";
const StudentList = ({ students = [], setStudentsList }) => {
return (
<div>
{students.map((student) => (
<ul key={student.id}>
<li>
<p>{student.name}</p>
</li>
</ul>
))}
</div>
);
};
export default StudentList;
So you want to show the form if not submitted and show the list if submitted? You can add a piece of state called submitted and do simple conditional rendering.
const StudentListResult = () => {
const [submitted, setSubmitted] = useState(false)
return (
{submitted ? <StudentList /> : <StudentListForm />}
);
};
And then in your addStudent function, set submitted.
const addStudent = (event) => {
// ...
setSubmitted(true)
}
If you want change form and list visibility state, you need pass custom function to form component:
StudentListResult.jsx:
const StudentListResult = () => {
const [newStudent, setNewStudent] = useState("");
const [students, setStudentsList] = useState([]);
const [getFormSubmitted, setFormSubmitted] = useState(false);
const setCompletedForm = () => {
setFormSubmitted(!getFormSubmitted);
};
return (
<div>
{getFormSubmitted ? (
<div>
<StudentList students={students} setStudentsList={setStudentsList} />
</div>
) : (
<div>
<StudentForm
newStudent={newStudent}
setNewStudent={setNewStudent}
students={students}
setStudentsList={setStudentsList}
onComplete={setCompletedForm}
/>
</div>
)}
</div>
);
};
Then call this function if form is submitted and all conditions is true
StudentListForm.tsx:
const StudentListForm = ({
newStudent,
setNewStudent,
students,
setStudentsList,
onComplete
}) => {
const addStudent = (event) => {
event.preventDefault();
setStudentsList([...students, { id: uuidv4(), name: newStudent }]);
setNewStudent("");
onComplete();
};
I need to update the value of Form.Item manually. I have a custom component, which returns selected value, and want to pass this value to the Form for validation and so I can send it.
Is this possible with antd?
Here's the simplified code:
import { Form } from "antd";
import { FC, ReactElement, useEffect, useState } from "react";
const Child: FC<{
returnValue: (value: any) => void;
}> = ({ returnValue }): ReactElement => {
return <input onChange={(e) => returnValue(e.currentTarget.value)} />;
};
export default function App() {
const { useForm } = Form;
const [form] = useForm();
const [value, setValue] = useState<string>("");
const setNewValue = (newVal: string) => setValue(newVal);
useEffect(() => {
console.log(value);
}, [value]);
return (
<div className="App">
test
<Form form={form}>
<Form.Item
//value={value} I'm looking form smth like this
>
<Child returnValue={setNewValue} />
</Form.Item>
</Form>
</div>
);
}
And here is the code sandbox.
Using <Input> from antd will not work in my case. This is a simplified problem. I have a way more complex component, which behaves in a similar way. The returnValue is how I managed to pull the value out of the component.
For a class based component, this is how you would define a form
class CustomForm extends React.Component {
formRef = React.createRef();
constructor()
render(){
return(
<Form
ref={this.formRef}
name="customForm"
>
<Form.Item label="Email" name="email">
<Input />
</Form.Item>
</Form>
)}
}
and this is how you set form.items value
componentDidUpdate(){
this.formRef.current.setFieldsValue({
email: this.props.customerData.map((d) => d.email),
});
}
you can convert the logic for the functional component.
I have a React Form app with name and description fields.
The form data is held in a local state object using Hooks:
const [data,setData] = useState({name: '', description: ''}).
The <Form /> element creates inputs and passes their value using <Field initialValue ={data.name} />
Within the <Field /> element, this initialValue is passed to the state, which controls the input value (updated onChange):
const [value,setValue] = useState(initialValue).
But if I reset the data object (see handleResetClick function), the inputs don't clear (even though the data object clears). What am I doing wrong? I thought that changing the data would cause a re-render and re-pass initialValue, resetting the input.
Codepen example here - when I type in the inputs, the data object updates, but when I click Clear, the inputs don't empty.
function Form() {
const [data, setData] = React.useState({name: '', description: ''});
React.useEffect(() => {
console.log(data);
},[data]);
const onSubmit = (e) => {
// not relevant to example
e.preventDefault();
return;
}
const handleResetClick = () => {
console.log('reset click');
setData({name: '', description: ''})
}
const onChange = (name, value) => {
const tmpData = data;
tmpData[name] = value;
setData({
...tmpData
});
}
return (
<form onSubmit={onSubmit}>
<Field onChange={onChange} initialValue={data.name} name="name" label="Name" />
<Field onChange={onChange} initialValue={data.description} name="description" label="Description" />
<button type="submit" className="button is-link">Submit</button>
<button onClick={handleResetClick} className="button is-link is-light">Clear</button>
</form>
)
}
function Field(props) {
const {name, label, initialValue, onChange} = props;
const [value, setValue] = React.useState(initialValue);
return (
<div>
<div className="field">
<label className="label">{label}</label>
<div className="control">
<input
name={name}
className="input"
type="text"
value={value}
onChange={e => {
setValue(e.target.value)
onChange(name, e.target.value)
}}
/>
</div>
</div>
</div>
)
}
class App extends React.Component {
render() {
return (
<div className="container">
<Form />
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
)
On handleResetClick you change the data state of Form, but it doesn't affect its children.
Try adding a listener for initialValue change with useEffect:
function Field(props) {
const { name, label, initialValue, onChange } = props;
const [value, setValue] = React.useState(initialValue);
useEffect(() => {
setValue(initialValue);
}, [initialValue]);
return ...
}
You may be better off having Field as a controlled component (ie it's state is managed by the parent component rather than maintaining its own state). In this example I've swapped in value instead of initialValue and simply passed that down as props to the field. onChange then calls the parent method and updates the state there (which is automatically passed back down to the field when it renders):
const { useState, useEffect } = React;
function Form() {
const [data, setData] = React.useState({
name: '',
description: ''
});
useEffect(() => {
console.log(data);
}, [data]);
const onSubmit = (e) => {
e.preventDefault();
return;
}
const handleResetClick = () => {
setData({name: '', description: ''})
}
const onChange = (e) => {
const { target: { name, value } } = e;
setData(data => ({ ...data, [name]: value }));
}
return (
<form onSubmit={onSubmit}>
<Field onChange={onChange} value={data.name} name="name" label="Name" />
<Field onChange={onChange} value={data.description} name="description" label="Description" />
<button type="submit" className="button is-link">Submit</button>
<button onClick={handleResetClick} className="button is-link is-light">Clear</button>
</form>
)
}
function Field(props) {
const {name, label, value, onChange} = props;
return (
<div>
<div className="field">
<label className="label">{label}</label>
<div className="control">
<input
name={name}
className="input"
type="text"
value={value}
onChange={onChange}
/>
</div>
</div>
</div>
)
}
function App() {
return (
<div className="container">
<Form />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I've been trying to learn React hooks in order to start building a personal project but ran into a few road blocks. Currently, when I do an axios request, the page resets and no data is shown.
In order to make sure it was working the correct way, I made a class version and was able to retrieve the data plus upload it to state with setState.
import React, { useState } from "react";
import axios from "axios";
const Form = () => {
const [signup, setForm] = useState({ username: "", email: "", password: "" });
const [user, setUser] = useState({ user: "" });
const submit = () => {
axios.get("/api/users").then(user => {
setUser({ user });
});
};
return (
<div>
{user.username}
<h1>This is the Landing Page!</h1>
<form onSubmit={submit}>
<input
type="text"
placeholder="Enter Username"
value={signup.username}
onChange={e => setForm({ ...signup, username: e.target.value })}
/>
<input
type="text"
placeholder="Enter Email"
value={signup.email}
onChange={e => setForm({ ...signup, email: e.target.value })}
/>
<input
type="password"
placeholder="Enter Your Password"
value={signup.password}
onChange={e => setForm({ ...signup, password: e.target.value })}
/>
<input type="submit" value="Submit" />
</form>
</div>
);
};
The class option works
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
user: ""
};
}
loadData = () => {
console.log(this.state);
axios.get("/api/users").then(user => {
console.log(user.data);
debugger;
this.setState({ user });
});
};
render() {
return (
<div>
<h1>This is the header</h1>
<button onClick={this.loadData}>This is a button</button>
</div>
);
}
}
What I'm expecting is for the data to persist. It does appear in console.log but even that disappears within a few seconds as if the entire page keeps reloading. When I do input typing it works but not on a axios call.
Change your onSubmit function to the following to avoid a page reload.
const submit = (e) => {
e.preventDefault();
axios.get("/api/users").then(user => {
setUser({ user });
});
};
You want to disable the browser from submitting the form by adding an event.preventDefault(), and let your submit() function send that request with Axios (or fetch) instead:
const submit = event => {
event.preventDefault();
...
}