Redux form cannot type - reactjs

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.

Related

Redux-Form is not connected to Router correctly

I'm trying to initialize data into form, show the form and navigate to other component (manually). After I successfully load data into form I found myself in a dead end, that I am unable to navigate to another component because I am getting TypeError: path.lastIndexOf is not a function error.
I am using redux-form and component is connected via withRouter.
I tried to workaround it with changing to React.Component, but after I managed to get data into form and connect component with Router, data in the form was unable to change (I was unable to even interact with the form). So I switched back to old solution that gave me that error.
Used versions:
"react-redux": "^6.0.0",
"react-router-dom": "^4.3.1",
"redux": "^4.0.1",
"redux-form": "^8.1.0",
"redux-thunk": "^2.3.0",
userProfile.jsx
const renderField = ({
input,
label,
placeholder,
type,
meta: { touched, error },
...rest
}) => (
<div>
<label htmlFor={label}>{label}</label>
<div>
<input {...input} {...rest} type={type} />
{touched
&& ((error && <span className="error-text">{error}</span>))}
</div>
</div>
);
let userProfile = (props) => {
const {
handleSubmit, pristine, submitting, reset,
} = props;
const confirmTitle = 'Are you sure about clearing the changed values?';
const confirmDescription = 'Please notice that you can lose the data you edited';
return (
<div className="container__form" style={{ height: '160vh' }}>
<Confirm title={confirmTitle} description={confirmDescription}>
{ confirm => (
<form className="extended-form" onSubmit={handleSubmit}>
<h3> Personal Data </h3>
<div className="form-control">
<Field
name="username"
type="text"
component={renderField}
label="User name"
disabled
/>
</div>
<div className="form-control">
<Field
name="email"
type="text"
component={renderField}
label="E-mail"
disabled
/>
</div>
<div className="form-control">
<Field
name="user.firstName"
type="text"
component={renderField}
label="First Name"
validate={required()}
/>
</div>
<div className="form-control">
<Field
name="user.lastName"
type="text"
component={renderField}
label="Last Name"
validate={required()}
/>
</div>
<div>
<div className="form-actions">
<button type="submit" disabled={submitting}>
Submit
</button>
{/* </div>
<div className="form-actions"> */}
<button type="button" disabled={pristine || submitting} onClick={confirm(() => reset())}>
Cancel
</button>
</div>
</div>
</form>
)}
</Confirm>
</div>
);
};
export default compose(
withRouter,
connect(
state => ({
...state,
initialValues: state.user.data,
}),
),
reduxForm({
form: 'userProfileForm',
enableReinitialize: true,
}),
)(userProfile);
UserProfileComponent.jsx
const UserProfileComponent = (props) => {
const sendData = (data) => {
props.clearErrors();
props.updateUserData(data);
};
const { errors } = props;
return (
<div className="extended">
<h2> Extended Register process </h2>
<div className="tooltip"> i </div>
<span className="pale-magenta-text"> The mandatory fills are indicated by a * in the right site of the field name </span>
<UserProfile onSubmit={sendData} />
<br />
{errors && (<div className="error-text">{errors.error}</div>)}
</div>
);
};
const mapStateToProps = state => ({
...state,
errors: state.errors,
});
const mapDispatchToProps = dispatch => ({
updateUserData: data => dispatch(updateUserData(data)),
clearErrors: () => dispatch(clearErrors()),
});
export default connect(
mapStateToProps,
mapDispatchToProps,
)(UserProfileComponent);
I expect initialize of the form to be working and also, that I am connected to the Router correctly.
The problem is I think in HOC, because when I change the order of reduxForm and connect, I can navigate but I cannot see any data initialized into form. But that's sadly my dead end I cannot move from. Thanks a lot for any help or suggestion.
I did a lot of debug and changes and finally I found a way how to make it all work.
It's maybe not the best answer, but it can help someone with the same problem:
I removed withRouter (as it was not needed anymore) and changed the order of HOC in UserProfile.jsx to match:
export default compose(
reduxForm({
form: 'userProfileForm',
enableReinitialize: true,
}),
connect(
state => ({
...state,
initialValues: state.user.data,
}),
),
)(userProfile);
I hard coded initialValues in UserProfileComponent.jsx* to match:
<UserProfile onSubmit={sendData} initialValues={props.user.data}/>
Now the data is loaded, user can interact with the form (validation is working) and also, user can fully navigate in the site with no errors.
I hope it helps someone to solve same or similar problem that I had.
Enjoy

Cannot get the form values in redux form?

I'm creating a simple login form using react and redux form.
When I try to console the values entered in the form, I get undefined.
import React, { Component } from 'react';
import { reduxForm } from 'redux-form';`enter code here`
class Signin extends Component {
handleFormSubmit({email, password}){
console.log(email,password);
// this.props.signinUser({email,password});
}
render(){
const { handleSubmit, fields: { email, password }} = this.props;
return (
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<fieldset className="form-group">
<label>Email:</label>
<input className="form-control" {...email} />
</fieldset>
<fieldset className="form-group">
<label>Password:</label>
<input className="form-control" {...password} />
</fieldset>
<button action="submit" className="btn btn-primary">Sign in</button>
</form>
);
}
}
export default reduxForm({
form: 'signin',
fields: ['email', 'password']
})(Signin);
I figured out the issue.
The tutorial I was following was one year old and was using an old version of Redux Form which accepts input in this form. But while installing the modules, I installed the latest version. Thanks.

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));

Form input using Redux Form not updating

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
});

Highly reusable react component without any code change and use only properties

I would like to create a component which I can reuse also for other projects without any code change (only by passing different properties).
A small example:
I have a login form which has a username input and a password input which can look for example like this:
class Login extends Component {
static propTypes = {
login: PropTypes.func.isRequired,
defaultEmailValue: PropTypes.string,
defaultPasswordValue: PropTypes.string,
};
handleSubmit = (event) => {
if (event) {
event.preventDefault();
}
const username = this.refs.username;
const password = this.refs.password;
this.props.login(username.value, password.value);
};
render() {
const {
defaultEmailValue,
defaultPasswordValue,
} = this.props;
return (
<form method="post">
<input defaultValue={defaultEmailValue} ref="username" type="email" />
<input defaultValue={defaultPasswordValue} ref="password" type="password" />
<button onClick={this.handleSubmit} type="submit">Submit</button>
</form>
);
}
}
This is the minimal version of a login form, but what to do when I want to extend the render function to add container components like this (added column tags):
class Login extends Component {
/*....*/
render() {
const {
defaultEmailValue,
defaultPasswordValue,
} = this.props;
return (
<form method="post">
<div class="row">
<div class="col-md-6">
<input defaultValue={defaultEmailValue} ref="username" type="email" />
</div>
<div class="col-md-6">
<input defaultValue={defaultPasswordValue} ref="password" type="password" />
</div>
</div>
<button onClick={this.handleSubmit} type="submit">Submit</button>
</form>
);
}
}
Therefore I have always to modify the render function. Is there a good possibility to do this only with properties?
I estimated to do this with a Wrapper-Component over the Login component but then I have always rewrite the complete render function.
The next possible solution I thought about is to pass wrapper component classes through properties which can be rendered. But is this so a good solution or is this bad practice?
Unfortunately, I found no real solution for this tutorial in the internet and therefore I try it here. Thanks in advance :-)
Is there a good possibility to do this only with properties?
Representational Components are exactly for this kind of things.
export default const LoginForm = (/**props**/ {username, email, submitHandler, errors}) => {
return (
<form>
{/* as usual */}
</form>
)
}
use in your ContainerComponent:
...
render() {
return (
<div className="loginWrapper">
<LoginForm ...this.props ...this.state ...whatever username="pete" />
</div>
)
}
...

Resources