react formik - fill form inputs with data after http request - forms

I created form with formik.
I want to edit record with the form. I want to fetch data from database and fill the form with them.
However with no success.
Here is my code.
class UserForm extends Component {
componentWillMount(){
this.setState({firstName:''})
var repository = new Repository();
repository.getUser(function(user){
this.setState({
firstName: user.firstName,
});
}.bind(this),this.props.currentId)
}
render() {
return (
<Formik
initialValues={{
firstName: this.state.firstName,
}}
validationSchema = {Yup.object().shape({
firstName: Yup.string().required('First name is required'),
})}
onSubmit={item => { this.props.addRecordToTable(item)}}
render={({ setFieldValue, values, errors, touched, isSubmitting }) =>
<Form>
<div>
{ touched.firstName && errors.firstName && <p>{errors.firstName}</p> }
<Field type="input" name="firstName" placeholder="First name"/>
</div>
<input type="submit"></input>
</Form>}
/>
);
}
}
export default UserForm;
Input firstName will never be filled with loaded data.
How can i solve this?

Set enableReinitialize to true in <Formik ... />

Related

react-semantic-ui-datepickers no form value in redux-form

This issue applied the standard implementation without additional customisations.
The is no value on submit of the form and onChange does not fire with the current value.
<Form onSubmit={handleSubmit(this.onSubmit)}>
<Form.Group>
<Field
component={SemanticDatepicker}
name="working"
dateFormat="DD/MM/YYYY"
label="Date of birth"
placeholder="select your DOB"
size="small"
onChange={(e, value) => {
console.log(e, value);
}}
/>
</Form.Group>
<Form.Field
control={Button}
color="purple"
className="submit-btn"
type="submit"
width={6}
>
Save
</Form.Field>
</Form>
A minimal version can be found here https://github.com/chrishj59/datepickerIssue
I could capture the onChange value by creating a custom component which wrapped the <SemanticDatepicker />. I also added mapStateToProps to log the redux-form values. You can consider this as a starting point and work on this.
//SongList.js
state = {
date: "",
};
render(){
const DatePick = () => {
return (
<SemanticDatepicker
onChange={this.datePickerOnChange}
format="YYYY-MM-DD"
/>
);
};
return (
<Form onSubmit={handleSubmit(this.onSubmit)}>
<Form.Group>
<Field
component={DatePick}
name="working"
dateFormat="DD/MM/YYYY"
label="Date of birth"
placeholder="select your DOB"
size="small"
/>
</Form.Group>
<Form.Field
control={Button}
color="purple"
className="submit-btn"
type="submit"
width={6}
>
Save
</Form.Field>
</Form>
);
}
//App.js
import { connect } from "react-redux";
const App = (props) => {
console.log(props.form);
return (
<div>
{" "}
<SongList />
</div>
);
};
const mapStateToProps = (state) => ({
form: state.form,
});
export default connect(mapStateToProps)(App);
I managed to resolve using semantic-ui-redux-form-fields to wrap the Semantic UI component. This now gives the correct format and value appearing in the validate function and formProps.
import React from "react";
imp ort { fieldEnhance } from "semantic-ui-redux-form-fields";
import { compose } from "redux";
import SemanticDatepicker from "react-semantic-ui-datepickers";
import "react-semantic-ui-datepickers/dist/react-semantic-ui-datepickers.css";
const DatePickerPure = (props) => {
const { currentValue, input, ...rest } = props;
const defaultProps = {
format: "DD/MMM/YYYY",
onChange: (event, data) => input.onChange(data.value),
value: currentValue,
...rest,
};
return <SemanticDatepicker {...props} {...defaultProps} />;
};
export default compose(fieldEnhance)(DatePickerPure);

React POST request input value is wrong

So I'm trying to add a NewPost and I'm getting the :
"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."
...error when it says "this.state.title"
Ps: I'm using nodejs, mongodb and react
e.preventDefault();
const newPost = {
title: this.state.title,
typeOfProduction: this.state.typeOfProduction
};
Here's my code:
import React, { Component } from 'react';
import './NewPost.css';
class NewPost extends Component {
state = {
posts:{
title: '',
typeOfProduction: ''
}
}
postDataHandler(e) {
e.preventDefault();
const newPost = {
title: this.state.title,
typeOfProduction: this.state.typeOfProduction
};
fetch('/projects', {
method: 'POST',
body: JSON.stringify(newPost),
headers: {
'Content-Type': 'application/json'
}
}).then(console.log);
}
render(){
return(
<div className="Dashboard container-fluid">
<div className="NewPost">
<h1>Add a Post</h1>
<label>Title</label>
<input type="text" value={this.state.title} name="title" ref="title" onChange={(event) => this.setState({title: event.target.value})} />
<label>Type of Production</label>
<select value={this.state.typeOfProduction} name="typeOfProduction" ref="typeOfProduction" onChange={(event) => this.setState({typeOfProduction: event.target.value})}>
<option value="Fiction">Fiction</option>
<option value="Tv">TV</option>
<option value="Tv">Documentary</option>
</select>
<button type="submit" onClick={this.postDataHandler}>Add Post</button>
</div>
</div>
);
}
}
export default NewPost;
initialize state like this, remove posts.
state = {
title: '',
typeOfProduction: ''
}

Redux Form Values Properties Undefined & Refreshes on Submit

I am using redux-form in order to submit a new user signup page in my React Web App, but when I try to grab the input field values on the form of the parameter values, it comes back undefined in mapDispatchToProps. I have read many posts of people claiming their values variable comes back undefined, but that is not the case for me. Only when I console.log(values.[inputName]) do I get undefined. According to the documentation, I cannot tell that I am doing anything incorrectly.
Can someone please help determine what is causing values.email to be undefined? Thanks.
// presentational component
class Signup extends Component {
render() {
const { handleSubmit } = this.props;
return (
<div>
<h1>Signup</h1>
<form onSubmit={handleSubmit}>
<div>
<label>
Email:
<Field component="input" type="email" name="email" />
</label>
</div>
<div>
<label>
Password:
<Field component="input" type="password" name="password" />
</label>
</div>
<button type="submit" >Submit</button>
</form>
</div>
)
}
}
export default reduxForm({
form: 'Signup',
enableReinitialize: true
})(Signup)
// redux container component
const mapDispatchToProps = (dispatch) => {
return {
handleSubmit: (values) => {
console.log(values.email); // outputs undefined!
}
};
}
const SignupContainer = connect(
null,
mapDispatchToProps
)(Signup)
export default SignupContainer;
// reducer index.js
import { reducer as formReducer } from 'redux-form';
export const appReducer = combineReducers({
form: formReducer
})
// store.js
export const store = createStore(
appReducer,
applyMiddleware(
thunkMiddleware,
loggerMiddleware
)
);
Side Note
I have noticed that whenever I first click the submit button on the form, the page refreshes (so I do not see the console.log). All proceeding times does not cause a refresh, but I am unsure as to why. Any explanation of this would be greatly appreciated, too.
Update
After changing my Router from HashHistory to BrowserRouter (react-router), the page refreshes every time I click submit. Seems that I have two problems now.

React updating state in two input fields from form submission

I am trying to make a simple contact form using React. Eventually I will send the data collected from the state to a database, but for right now I am trying to just get it to console log the correct values.
Right now, the email field overrides the name field and when I console log both states, name shows up and email is undefined. Here is my React Component
import React, { Component, PropTypes } from 'react';
import ContactData from '../data/ContactData.js';
class FormContact extends Component {
constructor(props) {
super(props)
this.state = {
name: '',
email: '',
textArea: ''
}
}
handleChange(event) {
event.preventDefault();
this.setState({
name: event.target.value,
email: event.target.email
})
}
handleSubmit(event) {
event.preventDefault();
console.log(this.state.name + ' ' + this.state.email);
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<label> Name:
<input type="text" placeholder="Name" value={this.state.name} onChange={this.handleChange.bind(this)} />
</label><br />
<label> Email:
<input type="text" placeholder="Email" value={this.state.email} onChange={this.handleChange.bind(this)}/>
</label><br />
<input className="btn btn-primary" type="submit" value="Submit" />
</form>
)
}
}
FormContact.PropTypes = {
subName: PropTypes.string,
subEmail: PropTypes.string
}
FormContact.defaultProps = {
subName: 'Sam',
subEmail: ''
}
class Contact extends Component {
render() {
return (
<div>
<h1>CONTACT PAGE</h1>
<FormContact />
</div>
)
}
}
export default Contact;
If I understand what you want, you could do it as follows :
Add an empty object in your state for the form values
formValues: {}
Add the name attribute to your fields
<input name="name" .... />
<input name="email" .... />
then depending on that name update your state in handleChange function
let formValues = this.state.formValues;
let name = event.target.name; // Field name
let value = event.target.value; // Field value
formValues[name] = value;
this.setState({formValues})
And if the values go one level deeper, you could use
value={this.state.formValues["name"]} instead of value={this.state.name} - where name is the value of the name attribute of your input field
Thus, everything together should be as follows :
class Test extends React.Component {
constructor(props) {
super(props)
this.state = {
formValues: {}
}
}
handleChange(event) {
event.preventDefault();
let formValues = this.state.formValues;
let name = event.target.name;
let value = event.target.value;
formValues[name] = value;
this.setState({formValues})
}
handleSubmit(event) {
event.preventDefault();
console.log(this.state.formValues);
}
render(){
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<label> Name:
<input type="text" name="name" placeholder="Name" value={this.state.formValues["name"]} onChange={this.handleChange.bind(this)} />
</label><br />
<label> Email:
<input type="text" name="email" placeholder="Email" value={this.state.formValues["email"]} onChange={this.handleChange.bind(this)}/>
</label><br />
<input className="btn btn-primary" type="submit" value="Submit" />
</form>
)
}
}
React.render(<Test />, document.getElementById('container'));
Here is fiddle.
Hope this helps.
The reference to event.target.email does not exist on the event element. The value of a text input from an inline-event handler would be event.target.value for both email and name. The quick solution is to create a separate handler for each input:
handleChangeName(event) {
event.preventDefault();
this.setState({ name: event.target.value }); //<-- both use the same reference
} // to get the contextual value
handleChangeEmail(event) { // from the inputs v
event.preventDefault(); // |
this.setState({ email: event.target.value }); //<--------------------
}

Nested form state and one onChange function in React

I'm working on a form in React. I have nested state in MatchForm component and "bind" values from state with different inputs. I would like to have on onChange function which manages all cinput changes and pass it to state. Current onChange function works when I have only lineup inputs. But when I added other inputs I have no idea how to handle with it. How should I name inputs and how onChange function should look like to work with all inputs (without many ifs)?
Thank you in advance
class MatchForm extends React.Component {
constructor(props) {
super(props);
this.state = {
lineup: {
setter: '',
receiver1: '',
receiver2: '',
attacker: '',
blocker1: '',
blocker2: '',
libero: ''
},
distribution: {
receiver1: 20,
receiver2: 20,
attacker: 20,
blocker1: 20,
blocker2: 20
},
risk: 'normal',
default: false
};
this.onChange = this.onChange.bind(this);
}
onChange(e) {
this.setState({lineup: { ...this.state.lineup, [e.target.name]:e.target.value } })
}
render() {
return (
<div>
{
Object.keys(this.state.lineup).map((el,i) =>
<select
key={i}
name={el}
onChange={this.onChange}
value={this.state.lineup[el]}
>
<option value="" disabled>{el}</option>
<option value="Marian Noga">Marian Noga</option>
<option value="Janek Kowalski">Janek Kowalski</option>
</select>
)
}
{
Object.keys(this.state.distribution).map((el,i) =>
<Field
key={i}
field={el}
label={el}
type='number'
value={this.state.distribution[el]}
onChange={this.onChange} />
)
}
<select
name="risk"
onChange={this.onChange}
value={this.state.risk}
>
<option value="" disabled>risk</option>
<option value="safe">safe</option>
<option value="normal">normal</option>
<option value="risk">risk</option>
</select>
<label><input name="default" type="checkbox" value={this.state.default} onChange={this.onChange} /> Set as default lineup</label>
</div>
)
}
}
export default MatchForm
You can bind the onChange function with different values for each of your fields:
onChange={this.onChange.bind(this, 'lineup', el)}
Then if you write your onChange like this:
onChange(field, name, e) {
this.setState({[field]: { ...this.state[field], [name]:e.target.value } });
}
You should be able now to repeat that for each of your fields.
If it is just a controlled input, and no other UI logic, I do something as simple as this:
<input type="text"
name="email"
value={this.state.email}
onChange={e => this.setState({ email: e.target.value })}
/>
You could also try _.set for more complex use cases. Good thing is, the set function alone can be downloaded as an npm package
<input type="text" name="lineup.receiver1" onChange={handleChange} value={this.state.lineup.receiver1} />
import update from "lodash.set";
const handleChange = (ev) => { update(this.state, ev.target.name, ev.target.value ) }
_.set has more complex options for updating a nested object and can be used in our case with HTML name property of a field.