Form input using Redux Form not updating - reactjs

My input field is not updating on key press:
import React, { Component, PropTypes } from 'react';
import { Field, reduxForm } from 'redux-form';
class CitySelector extends Component {
render() {
const { isFetching, pristine, submitting, handleSubmit } = this.props;
return (
<form className="form-horizontal col-xs-offset-1" onSubmit={handleSubmit(this.fetchWeather)}>
<div className="form-group">
<div className="col-md-4 col-xs-4">
<Field name="city"
component={city =>
<input type="text" className="form-control" {...city.input} placeholder="enter a city for a 5 day forecast"/>
}
/>
</div>
<div className="col-md-3 col-xs-3">
<button type="submit" className="btn btn-success">Submit</button>
</div>
</div>
</form>
);
}
}
export default reduxForm({
form: 'cityForm'
})(CitySelector);
Do I need to supply an onChange handler for text inputs?

I was having the same problem and my mistake was very simple.
Here's what I had:
import { combineReducers } from 'redux';
import { reducer as forms } from 'redux-form';
import otherReducer from './otherReducer';
export default combineReducers({ otherReducer, forms });
Notice that I was importing redux-form reducer as forms and passing it as is to my combineReducers (like I did with otherReducer) using ES6 Object property value shorthand.
The problem is that the key used to pass redux-form reducer to our combineReducers MUST be named form, so we have to change it to:
export default combineReducers({ customer, form: forms });
or
import { reducer as form } from 'redux-form';
export default combineReducers({ otherReducer, form });
Hope this helps someone else...

If you are using immutable data structures, instead of:
import { reduxForm } from 'redux-form';
use this:
import { reduxForm } from 'redux-form/immutable';
See here for more info http://redux-form.com/6.7.0/examples/immutable/

I was just having an issue similar to this question, except my form wasn't submitting and my validate function also wasn't firing.
It was due to this:
I changed it from input to something else and it totally broke redux-form SILENTLY
const TextInput = ({
input, <--- DO NOT CHANGE THIS
placeholder,
type,
meta: { touched, error, warning }
}) => {
return (
<div className="row-md">
<input
placeholder={placeholder}
type={type}
className="form-text-input primary-border"
{...input} <--- OR THIS
/>
{touched && ((error && <span>{error}</span>) || (warning && <span>{warning}</span>))}
</div>
)
}
Here's the rest of my input if anyone wants to study it:
<Field
component={TextInput}
type="tel"
name="person_tel"
placeholder="Mobile Phone Number"
value={this.props.person_tel}
onChange={(value) => this.props.updateField({ prop: 'person_tel', value })}
/>

If you supply a custom input component to the Field, then yes you have to call onChange passed within input prop to your component. In fact, you almost got it right by spreading city.input, but there's a catch.
When you define a stateless component (or just any function) inside render() method, it is recreated upon every render. And because this stateless component is passed as a prop (component) to Field, it forces Field to render after each recreation. So, your input is going to lose focus whenever CitySelector component renders, thus, no key presses will be captured.
You should extract your stateless component into a separate definition:
const myInput = ({ input }) => (
<input type="text" className="form-control" {...input} placeholder="enter a city for a 5 day forecast" />
);
class CitySelector extends Component {
render() {
const { isFetching, pristine, submitting, handleSubmit } = this.props;
return (
<form className="form-horizontal col-xs-offset-1" onSubmit={handleSubmit(this.fetchWeather)}>
<div className="form-group">
<div className="col-md-4 col-xs-4">
<Field name="city" component={myInput} />
</div>
<div className="col-md-3 col-xs-3">
<button type="submit" className="btn btn-success">Submit</button>
</div>
</div>
</form>
);
}
}
It also makes your code more legible.
You can find more info on that problem in official docs of Redux Form. Note that you could probably use the default input without creating your own, take a look at simple form example.

I found out/ my problem was my
form: formReducer
was not in rootReducer.
formReducer must be on top. My case:
const rootReducer = combineReducers({
general: generalReducer,
data: combineReducers({
user:userReducer,
todoReducer
}),
form: formReducer
});

Related

Redux form cannot type

I cannot type in the text input of redux form.
it's a very minimal form
function Login({ handleSubmit, handleChange }) {
const [username, setUsername] = useState(undefined);
const [password, setPassword] = useState(undefined);
const onSubmit = (e) => {
console.log(e);
console.log(username);
console.log(password);
};
console.log(handleSubmit);
return (
<Container>
<div className={styles.centered}>
<div className={styles.form}>
<div className={styles.title}>
<H3>Login</H3>
</div>
<form onSubmit={() => handleSubmit(onSubmit)} className={styles.flexColumn}>
<div className={styles.username}>
<P>username</P>
<Field name="username" component="input" type="text" className={styles.input} />
</div>
<div className={styles.password}>
<P>password</P>
<Field name="password" component="input" type="password" className={styles.input} />
</div>
<div className={styles.downSection}>
<Flex>
<P>
Serve Aiuto?
</P>
<a href="#">
<div className={styles.contactLink}>
<P>Contattaci</P>
</div>
</a>
</Flex>
<Button type="submit" text="Accedi" />
</div>
</form>
</div>
</div>
</Container>
);
}
const mapDispatchToProps = {
login: loginAction,
};
const enhance = compose(
connect(null, mapDispatchToProps),
reduxForm({ form: 'login' }),
);
export default enhance(Login);
The handleSubmit doesn't work, i cannot console.log anything.
I tried to see the documentation and tried to search some answer on SO but i didn't find an answer.
Could you please tell me where is the error ? thanks.
So give this a try, let's leave enhance out, I don't know what it does honestly so let's try this type of Login configuration where we turn the component into a class-based one which is good practice anyway since you are receiving inputs from a user.
I do realize you are using useState which is some of the cool new features with React, but what I am recommending is to put together a less complex and conventional setup with a class-based component like so:
import React, { Component } from "react";
import { reduxForm, Field } from "redux-form";
class Login extends Component {
render() {
return (
<form>
<fieldset>
<label>Email</label>
<Field
name="email"
type="text"
component="input"
/>
</fieldset>
<fieldset>
<label>Password</label>
<Field
name="password"
type="password"
component="input"
/>
</fieldset>
</form>
);
}
}
export default reduxForm({ form: "login" })(Login);
Use this to check to see if you can now type into your inputs and then start adding stuff back in and test it every single time until you find the cause of the problem.
Try first just to handle the event
<form onSubmit={onSubmit} className={styles.flexColumn}>
after that try using the this in the function onsubmit and remove the const
onSubmit(event){
console.log(e);
console.log(username);
console.log(password);
this.handleSubmit(event.target.value);
};
after several hours and a special night of bug fixing i discovered the problem:
it was in one import, exactly:
import { Field, reduxForm } from 'redux-form/immutable';
and not
import { Field, reduxForm } from 'redux-form';
this was completely unexpected, i was pretty sure that the mistake was in the body of the component, not in the import.
the structure of the file was ok.

Transform Function Component -> Class Component

How to transform this function complement to class component
:
const SyncValidationForm = (props) => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form className ="formmailforbook" onSubmit={handleSubmit(submit)}>
<Field name="email" type="email" component={renderField} label="Email"/>
<div>
<button className ="hero_button margin_left" type="submit" disabled={submitting}>Submit</button>
</div>
</form>
)
}
Pretty easy translation, you can do the same prop destructuring in the render method. Only slight change is that now it's pulling from this.props:
import React, { Component } from 'react';
export default class SyncValidationForm extends Component {
render () {
const { handleSubmit, pristine, reset, submitting } = this.props;
return (
<form className ="formmailforbook" onSubmit={handleSubmit(submit)}>
<Field name="email" type="email" component={renderField} label="Email"/>
<div>
<button className ="hero_button margin_left" type="submit" disabled={submitting}>Submit</button>
</div>
</form>
)
}
}
It's pretty much easy.. copy the code to the new file and add export defaultbefore const something like this.
export default const SyncValidationForm
Import the file as you import other components where ever you want the component and use the imported name as jsx name as usal and provide props.

Set select default value doesn't work

Using Bulma CSS for a little help I made custom component to make me handle different kind of inputs with redux-form.
I would like to setup a default value for a select input.
import React from 'react';
import { Field } from 'redux-form';
const DropDownItem = ({ spec }) => {
const { name, defaultValue, items, iconLeft } = spec;
return (
<div className="field">
<div className="control has-icons-left">
<div className="select is-fullwidth">
<Field name={name} value={defaultValue} component="select">
{/* loop for countries */}
{items.map((country, i) => (
<option value={country} key={i}>
{country}
</option>
))}
</Field>
</div>
<div className="icon is-left">
<i className={iconLeft} />
</div>
</div>
</div>
);
};
export default DropDownItem;
I have the right value in defaultValue but the dropdown doesn't select this value by default.
The value of a <Field /> is controlled by the value in the redux-form store. You should set the initialValues for your redux-form form in the config when you initialize it:
import React from 'react'
import { Field, reduxForm } from 'redux-form'
let MyFormComponent = props => {
const { handleSubmit } = props;
return (
<form onSubmit={handleSubmit}>
<Field name="fieldName" component="input" /> // this field's default value will be 'defaultValue', as set in initialValues
...
</form>
)
}
MyFormComponent = reduxForm({
form: 'myForm',
initialValues: {
'fieldName': 'defaultValue',
...
}
})(MyFormComponent)
export default MyFormComponent;
You can also pass initialValues as a prop to your form component.
source
Seems like defaultValue has been disable in redux-form according to this thread on Github
Instead you can make use the initialValues API of redux-form
You can read more about initialValues on Redux Form Docs or initializefromstate

How to get Redux Form data in another Component

How can i pass the data from redux form, So that i can access that data in App.js?
here is the code i have written using redux-form.after i click on submit the data should be passed from form.js to app.js. and the data should be displayed on page.
here is form.js-
const Form=({fields:{name,address}})=>(
<form>
<center>
<div>
<label>First Name</label>
<Field type="text" component="input" placeholder="Name" name="name"/>
</div>
<div>
<label>Address</label>
<Field type="text" component="input" placeholder="Phone" name="phone" />
</div>
<button type="submit">Submit</button>
</center>
</form>
)
export default reduxForm({
form: 'form',
fields: ['name', 'address']
})(Form);
how can i pass this inputed data to app.js?
What you need to do is use getFormValues to get the redux field values
So in App.js you can have
import {getFormValues} from 'redux-form';
..
const App = (props) => {
var {name, phone} = props.formStates
console.log(name, phone);
}
function mapStateToProps(state) {
return {
formStates: getFormValues('form')(state) // here 'form' is the name you have given your redux form
}
}
export default connect(mapStateToProps)(App)
The above mentioned answer is absolutely correct however, when your form component gets unmounted the state may get destroyed and then it will not be available in any other component.To fix this you can add destroyOnUnmount: false to your reduxForm wrapper like this
export default reduxForm({
form: 'form',
destroyOnUnmount: false,
})(Form)
Now you can get the form data in any component by following the above answer. Hope this helps

How to handleSubmit with a redux-form

I'm working to use redux-form for the first time. I am able to render the form but I have not been able to handle the submit. While I eventually want to send the data to the server, at this point, I'm simply trying to console log the form field values. I'm getting the error:
Error: You must either pass handleSubmit() an onSubmit function or pass onSubmit as a prop
Here's my Profile.jsx file
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {withAuth} from 'react-devise';
import { Field, reduxForm } from 'redux-form';
class Profile extends Component {
handleSubmit(data) {
console.log('Submission received!', data);
}
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="firstName">First Name</label>
<Field name="firstName" component="input" type="text"/>
</div>
<div>
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" component="input" type="text"/>
</div>
<div>
<label htmlFor="email">Email</label>
<Field name="email" component="input" type="email"/>
</div>
<button type="submit">Submit</button>
</form>
);
}
}
// Decorate the form component
Profile = reduxForm({
form: 'profile' // a unique name for this form
})(Profile);
const mapStateToProps = state => {
return {
currentUser: state.currentUser
};
};
export default connect(mapStateToProps)(withAuth(Profile));
How can I handle the submitted values in a way where I can eventually send them to my API?
Redux-Form decorates your component with handleSubmit prop. According to docs it's:
a function meant to be passed to <form onSubmit={handleSubmit}> or to
<button onClick={handleSubmit}>. It will run validation, both sync and
async, and, if the form is valid, it will call
this.props.onSubmit(data) with the contents of the form data.
Optionally, you may also pass your onSubmit function to handleSubmit
which will take the place of the onSubmit prop. For example:
So if your component doesn't have onSubmit property you have to 'manually' pass your submit handler to handleSubmit function. Please try this:
<form onSubmit={this.props.handleSubmit(this.handleSubmit.bind(this))}>
Please don't confuse your handleSubmit method with prop passed from Redux-Form with the same name.
(Posted solution on behalf of the question author to move it to the answer space).
Working code:
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {withAuth} from 'react-devise';
import { Field, reduxForm } from 'redux-form';
class Profile extends Component {
handleSubmit(data) {
console.log('Submission received!', data);
}
render() {
return (
<form onSubmit={this.props.handleSubmit(this.handleSubmit.bind(this))}>
<div>
<label htmlFor="firstName">First Name</label>
<Field name="firstName" component="input" type="text"/>
</div>
<div>
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" component="input" type="text"/>
</div>
<div>
<label htmlFor="email">Email</label>
<Field name="email" component="input" type="email"/>
</div>
<button type="submit">Submit</button>
</form>
);
}
}
// Decorate the form component
Profile = reduxForm({
form: 'profile' // a unique name for this form
})(Profile);
const mapStateToProps = state => {
return {
currentUser: state.currentUser
};
};
export default connect(mapStateToProps)(withAuth(Profile));

Resources