On refresh react application I need to get from componentWillReceiveProps values for input text - forms

I have the following problem and I really need help on that.
export class DeviceEdit extends React.PureComponent<Props> {
constructor(props) {
super(props);
this.state = {
value: ''
};
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
let data = this.props.devices.data.find(device => device.id ===
`${deviceID}`) || {};
this.setState({ value: data.name })
}
componentWillMount() {
let data = this.props.devices.data.find(device => device.id ===
`${deviceID}`) || {};
this.setState({ value: data.name })
}
componentWillReceiveProps(newProps) {
let data = newProps.devices.data.find(device => device.id ===
`${deviceID}`) || {};
this.setState({ value: data.name })
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
const { error } = this.props;
return (
<FormLabel>Internal ID</FormLabel>
<input type="text" defaultValue={this.state.value} onChange= .
{this.handleChange} />
</Form.Label>)
}
}
So what I want is that when I refresh the page, I want to get the the this.state.value on my input.. which in this case I am not able to do that. So I would like to know what I am doing wrong here. If I set it on value on the input I did get what I want, but then I have an warning like that:
A component is changing an uncontrolled input of type checkbox 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
What can I do?

Actually, you should handle changes there and you can use just value on the input field instead of defaultValue.
For example:
export class AdminDeviceEdit extends React.PureComponent<Props> {
constructor(props) {
super(props);
this.state = {
value: '',
// if it comes from props by default
// you can use, if not just leave as it is
value: props.value
};
}
handleChange = e => {
this.setState({value: e.target.value});
}
render() {
const { error } = this.props;
return (
<form>
<FormLabel>Internal ID</FormLabel>
<input type="text" value={this.state.value} onChange={this.handleChange} />
</form>
)
}
}
Hope it will helps.

So from what I understand you want to make controlled input but use props.value as a default value. What if you do:
export class AdminDeviceEdit extends React.PureComponent<Props> {
constructor(props) {
super(props);
this.state = {
value: props.value,
};
this.handleChange = this.handleChange.bind(this);
}
componentWillReceiveProps(newProps) {
if(this.props.value !== newProps.value) {
this.setState({ value: newProps.value }) // reset input value
}
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
const { error } = this.props;
return (
<FormLabel>Internal ID</FormLabel>
<input type="text" value={this.state.value} onChange={this.handleChange} />
</Form.Label>)
}
}
Certainly get rid of componentWillMount and componentDidMount. You don't need them here.

Related

How to prevent repeating code of form validation

I created the form for multiple inputs, where the specific input data shall be validated at the time of data entry and once again for all data just before the submission of the form to the backend.
The conditions to submit: all fields are mandatory and the data is valid.
My program works, but I don't like that I'm repeating the validation code in 2 places: in ErrorOutput and hadleSubmit.
In ErrorOutput I check the data and, if necessary, display an error message.
In handleSubmit I just check the data without displaying of error message and if all data is valid, I confirm submitting.
How can I improve my example to prevent the repetition of this code, but the data validation was also at the time of data entry and before submission?
import React from 'react'
import { render } from 'react-dom'
const ErrorOutput = props => {
let name = props.name
let inputValue = props.case
let submit = props.submit
// Data validation
if (name === 'firstName') {
if (!inputValue.match(/^[a-zA-Z]+$/) && inputValue.length > 0) {
return <span>Letters only</span>
} else if (submit && inputValue.length === 0) {
return <span>Required</span>
}
return <span></span>
}
if (name === 'telNo') {
if(!inputValue.match(/^[0-9]+$/) && inputValue.length > 0) {
return <span>Numbers only</span>
} else if (submit && inputValue.length === 0) {
return <span>Required</span>
}
return <span></span>
}
}
class App extends React.Component {
constructor(props){
super(props)
this.state = {
firstName: '',
telNo: '',
submit: false
}
}
handleSubmit(e){
e.preventDefault()
let submit = true
let error = true
const { firstName, telNo } = this.state
this.setState ({submit: submit})
// Repeat the data validation before submission
if (firstName === '' || !firstName.match(/^[a-zA-Z]+$/)) {
error = true
} else if (telNo === '' || !telNo.match(/^[0-9]+$/)) {
error = true
} else {
error = false
}
// Submited if all data is valid
if (!error) {
// send data
return alert('Success!')
}
}
handleValidation(e) {
this.setState({
[e.target.name]: e.target.value
})
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<div>
<label>
First name:
</label>
<input
type='text'
name ='firstName'
value = {this.state.firstName}
onChange = {this.handleValidation.bind(this)}
/>
<ErrorOutput case={this.state.firstName} name={'firstName'} submit = {this.state.submit} />
</div>
<div>
<label>
Phone number:
</label>
<input
type='tel'
name ='telNo'
value = {this.state.telNo}
onChange = {this.handleValidation.bind(this)}
/>
<ErrorOutput case={this.state.telNo} name={'telNo'} submit = {this.state.submit} />
</div>
<button>
Submit
</button>
</form>
)
}
}
render(
<App />,
document.getElementById('root')
)
You could extract a FormItem component:
class FormItem extends React.Component {
render() {
return (
<div>
<label>
{this.props.label}
</label>
<input
{...this.props.input}
/>
<ErrorOutput
case={this.props.input.value}
name={this.props.input.name}
submit={this.props.onSubmit}
/>
</div>
);
}
}
and use it in your App:
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<FormItem label='First name:' input={{
type: 'text'
name: 'firstName'
value: this.state.firstName,
onChange: this.handleValidation.bind(this)
}}
onSubmit={this.state.submit}
/>
<FormItem label='Phone number:' input={{
type:'tel'
name :'telNo'
value : {this.state.telNo}
onChange : {this.handleValidation.bind(this)}
}}
onSubmit={this.state.submit}
/>
<button>
Submit
</button>
</form>
)
}
this is where libraries like react-final-form and redux-form become handy.
UPD
ErrorOutput component should not validate anything, it is not a responsibility of a component. Instead, you could validate your values on inputs blur event and before submit:
class App extends React.Component {
constructor(props){
super(props)
this.state = {
firstName: '',
telNo: '',
submit: false,
errors: {},
invalid: false,
}
}
handleSubmit(e){
e.preventDefault()
if (this.validate()) {
// handle error
} else {
// submit
}
}
validate = () => {
const { firstName, telNo } = this.state
const errors = {}
let invalid = false;
if (firstName === '' || !firstName.match(/^[a-zA-Z]+$/)) {
errors.firstName = 'first name is required'
invalid = true;
} else if (telNo === '' || !telNo.match(/^[0-9]+$/)) {
telNo.telNo = 'telNo is required'
invalid = true;
}
this.setState({
invalid,
errors,
})
return invalid;
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<FormItem label='First name:' input={{
type: 'text',
name: 'firstName',
value: this.state.firstName,
onChange: e => this.setState({ firstName: e.target.value }),
onBlur: () => this.validate(),
}}
/>
<FormItem label='Phone number:' input={{
type: 'tel',
name: 'telNo',
value: this.state.telNo,
onChange: e => this.setState({ telNo: e.target.value }),
onBlur: () => this.validate(),
}}
/>
<button>
Submit
</button>
</form>
)
}
}
and FormItem and ErrorOutput:
const ErrorOutput = ({ error }) => <span>{error}</span>
class FormItem extends React.Component {
render() {
return (
<div>
<label>
{this.props.label}
</label>
<input
{...this.props.input}
/>
{this.props.error && <ErrorOutput error={this.props.error} />}
</div>
);
}
}
const ErrorOutput = ({ errorText }) => <span>{errorText}</span>;
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
firstName: "",
telNo: "",
submit: false,
errors: {} //Add errors object to the state.
};
}
handleSubmit(e) {
e.preventDefault();
const errors = this.validateData();
if (Object.keys(errors).length === 0) {
alert("Success");
}
//else errors exist
this.setState({ errors });
}
validateData = () => {
let errors = {};
const { firstName, telNo } = this.state; // read the values to validate
if (firstName.length === 0) {
errors.firstName = "Required";
} else if (firstName.length > 0 && !firstName.match(/^[a-zA-Z]+$/)) {
errors.firstName = "Letters only";
}
if (telNo.length === 0) {
errors.telNo = "Required";
} else if (telNo.length > 0 && !telNo.match(/^[0-9]+$/)) {
errors.telNo = "Numbers only";
}
return errors;
};
handleValidation(e) {
this.setState({
[e.target.name]: e.target.value
});
}
render() {
const { errors } = this.state; // read errors from the state
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<div>
<label>First name:</label>
<input
type="text"
name="firstName"
value={this.state.firstName}
onChange={this.handleValidation.bind(this)}
/>
{errors.firstName && <ErrorOutput errorText={errors.firstName} />}
</div>
<div>
<label>Phone number:</label>
<input
type="tel"
name="telNo"
value={this.state.telNo}
onChange={this.handleValidation.bind(this)}
/>
{errors.telNo && <ErrorOutput errorText={errors.telNo} />}
</div>
<button>Submit</button>
</form>
);
}
}
render(<App />, document.getElementById("root"));

Form validation before the submission and at time of the data entry

I started to study React and wanted to create the form for multiple inputs, where I can check the validation of the data at the time of input and again before submitting of the form.
The conditions to submit: all fields are mandatory and the data is valid.
Currently, if user enters invalid data in input field, error text is displayed near the same field. And if user clicked button "submit" on the form with empty fields, error text is also displayed.
But I can't really work it out, how should I do the validation before the submission of the form in my example: : the form has the input field with an error or not.
import React from 'react'
import { render } from 'react-dom'
const ErrorOutput = props => {
let name = props.name
let inputValue = props.case
let submit = props.submit
console.log(props.submit)
if (name === 'firstName') {
if (!inputValue.match(/^[a-zA-Z]+$/) && inputValue.length > 0) {
return <span>Letters only</span>
} else if (submit && inputValue.length === 0) {
return <span>Required</span>
}
return <span></span>
}
if (name === 'telNo') {
if(!inputValue.match(/^[0-9]+$/) && inputValue.length > 0) {
return <span>Numbers only</span>
} else if (submit && inputValue.length === 0) {
return <span>Required</span>
}
return <span></span>
}
}
class App extends React.Component {
constructor(props){
super(props)
this.state = {
firstName: '',
telNo: '',
submit: false
}
}
handleSubmit(e){
e.preventDefault()
let submit = true
this.setState ({submit: submit})
// ... Validation
}
handleValidation(e) {
this.setState({
[e.target.name]: e.target.value
})
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<div>
<label>
First name:
</label>
<input
type='text'
name ='firstName'
value = {this.state.firstName}
onChange = {this.handleValidation.bind(this)}
/>
<ErrorOutput case={this.state.firstName} name={'firstName'} submit = {this.state.submit} />
</div>
<div>
<label>
Phone number:
</label>
<input
type='tel'
name ='telNo'
value = {this.state.telNo}
onChange = {this.handleValidation.bind(this)}
/>
<ErrorOutput case={this.state.telNo} name={'telNo'} submit = {this.state.submit} />
</div>
<button>
Submit
</button>
</form>
)
}
}
render(
<App />,
document.getElementById('root')
)
the following code is an example of adding data via form and form validation prior to the submit. More validations can be added.
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
age: '',
email: '',
errorName: '',
errorAge: '',
errroMail: '',
dataValue: false
};
this.getName = this.getName.bind(this);
this.getAge = this.getAge.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.postDatainDisplay = this.postDatainDisplay.bind(this);
}
componentWillReceiveProps(nextProps) {
if (this.props.name !== nextProps.name) {
this.setState({ dataValue: true });
}
}
postDatainDisplay(dataObj) {
this.props.postData(dataObj);
}
getName(event) {
const { name, age } = this.state;
this.setState({ errorName: '' });
this.setState({ name: event });
}
getAge(event) {
const { age } = this.state;
this.setState({ errorAge: '' });
this.setState({ age: event });
}
handleSubmit() {
const { name, age } = this.state;
//add more validation here
if (name === '') {
this.setState({ errorName: 'name cannot be blank', dataValue: false
});
} else if (age === '') {
this.setState({ errorAge: 'Age cannot be blank', dataValue: false });
} else
{ this.setState({ data: { name, age } }, () => {
this.props.sendData(this.state.data);
}
render() {
const { name, age } = this.props;
return (
<div className="container">
<form>
name:<input
type="text"
onChange={event => {
this.getName(event.target.value);
}}
/>
{this.state.errorName}
<br />
<br />
age:{' '}
<input
type="text"
onChange={event => {
this.getAge(event.target.value);
}}
/>
{this.state.errorAge}
<br />
<br />
<input type="button" onClick={this.handleSubmit} value="Submit"
/>
</form>
</div>
class App extends React.Component {
constructor(props){
super(props)
this.state = {
form:{
firstName: {
value: '',
validation: {
required: true
},
valid: false,
touched: false
},
telNo: {
value: '',
validation: {
required: true
},
valid: false,
touched: false
}
},
formIsValid:false
}
}
checkValidity(value, rules) {
let isValid = true;
if (rules.required) {
isValid = value.trim() !== '' && isValid;
}
return isValid;
}
handleValidation = (event) => {
let fieldName = event.target.name;
let fieldValue = event.target.value;
const updatedCategoryForm = {
...this.state.form
};
const updatedFormElement = {
...updatedCategoryForm[fieldName]
};
updatedFormElement.touched = true;
updatedFormElement.value = fieldValue;
updatedFormElement.valid = this.checkValidity(updatedFormElement.value, updatedFormElement.validation);
if (!updatedFormElement.valid && updatedFormElement.validation ) {
updatedFormElement.elementValidation = "Invalid";
} else {
updatedFormElement.elementValidation = "";
}
updatedCategoryForm[fieldName] = updatedFormElement;
let formIsValid = true;
for (let inputIdentifier in updatedCategoryForm) {
formIsValid = updatedCategoryForm[inputIdentifier].valid && formIsValid;
}
this.setState({ form: updatedCategoryForm, formIsValid: true });
}
Based on the value of formIsValid field disable submit button

React Form validation displaying error

I am using React-Validation-Mixin together with Joi and Joi-Validation-Strategy to do some validations on a React Step/Wizard Form.
I have a parent FormStart Element that receives the state of its FormStep children through props.
The validation correctly signals that the input is required, but when I write a correct number in the browser (5 numbers as in PLZ/ZIP-Code), it will still signal that the input is invalid, even though the zip state shows a correct 5-digit number, so the next button never takes me to the next Form step.
class FormStart extends Component {
constructor(props) {
super(props);
this.state = {
step: 1,
zip: ""
}
this.goToNext = this.goToNext.bind(this);
}
goToNext() {
const { step } = this.state;
if (step !== 10) {
this.setState({ step: step + 1 });
if (step == 9) {
const values = {
zip: this.state.zip,
};
console.log(values);
// submit `values` to the server here.
}
}
}
handleChange(field) {
return (evt) => this.setState({ [field]: evt.target.value });
}
render(){
switch (this.state.step) {
case 1:
return <FormButton
onSubmit={this.goToNext}
/>;
//omitting the other 8 cases
case 9:
return <FormStep7
onSubmit={this.goToNext}
zip={this.state.zip}
onZipChange={this.handleChange('zip')}
/>;
case 10:
return <FormSuccess/>;
}
}
}
export default FormStart;
The React console shows that the zip state is correctly changed, and the Validation object also receives the same correct 5-digit zip and still holds the correct value onBlur.
class FormStep7 extends Component {
constructor(props) {
super(props);
this.validatorTypes = {
PLZ: Joi.number().min(5).max(5).required().label('PLZ').options({
language: {
number: {
base: 'wird benötigt',
min: 'muss {{limit}} Nummern enthalten',
max: 'muss {{limit}} Nummern enthalten'
}
}
})
};
this.getValidatorData = this.getValidatorData.bind(this);
this.getClasses = this.getClasses.bind(this);
this.renderHelpText = this.renderHelpText.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
getValidatorData() {
return {
PLZ: this.props.zip
};
}
getClasses(field) {
return classnames({
'form-control': true,
'has-error': !this.props.isValid(field)
});
}
renderHelpText(message) {
return (
<span className='help-block'>{message}</span>
);
}
handleSubmit(evt) {
evt.preventDefault();
const onValidate = (error) => {
if (error) {
//form has errors; do not submit
} else {
this.props.onSubmit();
}
};
this.props.validate(onValidate);
}
render() {
return (
<form role="form" onSubmit={this.handleSubmit}>
<div className='row'>
<div className="col-md-10 col-md-offset-1">
<div className='form-group'>
<label htmlFor="zip">
Einsatzort
</label>
<br />
<input className={this.getClasses('PLZ')} id="PLZ" placeholder="Meine PLZ" type="text" onChange={this.props.onZipChange} onBlur={this.props.handleValidation('PLZ')} value={this.props.zip} />
{this.renderHelpText(this.props.getValidationMessages('PLZ'))}
</div>
</div>
</div>
<div className='row'>
<div className="col-md-10 col-md-offset-1">
<button className="btn btn-green btn-block">Next</button>
</div>
</div>
</div>
</form>
);
}
}
FormStep7.propTypes = {
errors: PropTypes.object,
validate: PropTypes.func,
isValid: PropTypes.func,
handleValidation: PropTypes.func,
getValidationMessages: PropTypes.func,
clearValidations: PropTypes.func
};
export default validation(strategy)(FormStep7);
What am I doing wrong?
I found out that the issue was on Joi.number(). I changed the validation to match a Regex String pattern and then it worked.
this.validatorTypes = {
PLZ: Joi.string().regex(/^[0-9]{5}$/).label('PLZ').options({
language: {
string: {
regex: {
base: "mit 5 Nummern wird benötigt"
}
}
}
})
};

How can I use props to auto-populate editable redux-form fields in React?

I'm new to React so I've tried to show as much code as possible here to hopefully figure this out! Basically I just want to fill form fields with properties from an object that I fetched from another API. The object is stored in the autoFill reducer. For example, I would like to fill an input with autoFill.volumeInfo.title, where the user can change the value before submitting if they want.
I used mapDispatchtoProps from the autoFill action creator, but this.props.autoFill is still appearing as undefined in the FillForm component. I'm also confused about how to then use props again to submit the form. Thanks!
My reducer:
import { AUTO_FILL } from '../actions/index';
export default function(state = null, action) {
switch(action.type) {
case AUTO_FILL:
return action.payload;
}
return state;
}
Action creator:
export const AUTO_FILL = 'AUTO_FILL';
export function autoFill(data) {
return {
type: AUTO_FILL,
payload: data
}
}
Calling the autoFill action creator:
class SelectBook extends Component {
render() {
return (
....
<button
className="btn btn-primary"
onClick={() => this.props.autoFill(this.props.result)}>
Next
</button>
);
}
}
....
function mapDispatchToProps(dispatch) {
return bindActionCreators({ autoFill }, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(SelectBook);
And here is the actual Form where the issues lie:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { reduxForm } from 'redux-form';
import { createBook } from '../actions/index;
class FillForm extends Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
}
onSubmit(props) {
this.props.createBook(props)
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
const { fields: { title }, handleSubmit } = this.props;
return (
<form {...initialValues} onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<input type="text" className="form-control" name="title" {...title} />
<button type="submit">Submit</button>
</form>
)
}
export default reduxForm({
form: 'AutoForm',
fields: ['title']
},
state => ({
initialValues: {
title: state.autoFill.volumeInfo.title
}
}), {createBook})(FillForm)
I think you're mixing up connect and reduxForm decorators in the actual form component. Currently your code looks like this (annotations added by me):
export default reduxForm({
// redux form options
form: 'AutoForm',
fields: ['title']
},
// is this supposed to be mapStateToProps?
state => ({
initialValues: {
title: state.autoFill.volumeInfo.title
}
}),
/// and is this mapDispatchToProps?
{createBook})(FillForm)
If this is the case, then the fix should be as simple as using the connect decorator as it should be (I also recommend separating this connect props to their own variables to minimize confusions like this):
const mapStateToProps = state => ({
initialValues: {
title: state.autoFill.volumeInfo.title
}
})
const mapDispatchToProps = { createBook }
export default connect(mapStateToProps, mapDispatchToProps)(
reduxForm({ form: 'AutoForm', fields: ['title'] })(FillForm)
)
Hope this helps!

React/Redux clear form elements values after submit

I have problems with clearing values from input and select form elements in react form after successful submit through axios library. Just want to mention that i do not use redux-form.
I don't know if I am on the right track here, this is my workflow by far: I wrote a form with react-bootstrap, give every input and select value through props and I access and update the state through these props. I have wrote actions and reducers for updating input values, and one action is dispatched in my component, but the second action and the reducer that is supposed to clear values after submit doesn't work as expected. This is the main problem, I'm not sure if I dispatch FORM_RESET action form in the right place, because I call it in the action that is responsible for posting data to server, and on success callback I dispatch FORM_RESET.
Below is the code relevant for this problem.
/* actionRegister.js */
let _registerUserFailure = (payload) => {
return {
type: types.SAVE_USER_FAILURE,
payload
};
};
let _registerUserSuccess = (payload) => {
return {
type: types.SAVE_USER_SUCCESS,
payload,
is_Active: 0,
isLoading:true
};
};
let _hideNotification = (payload) => {
return {
type: types.HIDE_NOTIFICATION,
payload: ''
};
};
//asynchronous helpers
export function registerUser({ //use redux-thunk for asynchronous dispatch
timezone,
password,
passwordConfirmation,
email,
name
}) {
return dispatch => {
axios.all([axios.post('/auth/signup', {
timezone,
password,
passwordConfirmation,
email,
name,
is_Active: 0
})
// axios.post('/send', {email})
])
.then(axios.spread(res => {
dispatch(_registerUserSuccess(res.data.message));
dispatch(formReset()); //here I dispatch clearing form data
setTimeout(() => {
dispatch(_hideNotification(res.data.message));
}, 10000);
}))
.catch(res => {
dispatch(_registerUserFailure(res.data.message)); //BE validation and passport error message
setTimeout(() => {
dispatch(_hideNotification(res.data.message));
}, 10000);
});
};
}
/* actionForm.js */
//synchronous action creators
export function formUpdate(name, value) {
return {
type: types.FORM_UPDATE_VALUE,
name, //shorthand from name:name introduced in ES2016
value
};
}
export function formReset() {
return {
type: types.FORM_RESET
};
}
/* reducerRegister.js */
const INITIAL_STATE = {
error:{},
is_Active:false,
isLoading:false
};
const reducerSignup = (state = INITIAL_STATE , action) => {
switch(action.type) {
case types.SAVE_USER_SUCCESS:
return { ...state, is_Active:false, isLoading: true, error: { register: action.payload }};
case types.SAVE_USER_FAILURE:
return { ...state, error: { register: action.payload }};
case types.HIDE_NOTIFICATION:
return { ...state , error:{} };
}
return state;
};
export default reducerSignup;
/* reducerForm.js */
const INITIAL_STATE = {
values: {}
};
const reducerUpdate = (state = INITIAL_STATE, action) => {
switch (action.type) {
case types.FORM_UPDATE_VALUE:
return Object.assign({}, state, {
values: Object.assign({}, state.values, {
[action.name]: action.value,
})
});
case types.FORM_RESET:
return INITIAL_STATE;
//here I need isLoading value from reducerRegister.js
}
return state;
};
export default reducerUpdate;
/* SignupForm.js */
import React, {Component} from 'react';
import {reduxForm} from 'redux-form';
import {connect} from 'react-redux';
import map from 'lodash/map';
import timezones from '../../data/timezones';
import styles from '../formElements/formElements.scss';
import {registerUser} from '../../actions/actionRegister';
import {formUpdate} from '../../actions/actionForm';
import FieldGroup from '../formElements/FieldGroup';
import { Form, FormControl, Col, Checkbox, Button, FormGroup } from 'react-bootstrap';
// {... props} passing large number of props wrap in object with spread notation
class SignupForm extends Component { //if component have state it needs to be class
constructor(props) {
super(props);
this.state = {
errors: { //this errors are irrelevant for now
name:'',
email: '',
password: '',
passwordConfirmation:'',
timezone:''
},
};
}
onChange = (event, index, value) => {
this.props.onChange(event.target.name, event.target.value);
};
onSave = (event) => {
event.preventDefault();
this.props.onSave(this.props.values);
}
render() {
let isLoading = this.props.isLoading;
return (
// this.props.handleSubmit is created by reduxForm()
// if the form is valid, it will call this.props.onSubmit
<Form onSubmit={this.onSave} horizontal>
<FieldGroup
id="formControlsName"
type="text"
label="Name"
name="name"
placeholder="Enter Name"
value={this.props.values[name]}
onChange={this.onChange}
help={this.state.errors.name}
/>
<FieldGroup
id="formControlsEmail"
type="text"
label="Email"
name="email"
placeholder="Enter Email"
value={this.props.values[name]}
onChange={this.onChange}
help={this.state.errors.email}
/>
<FieldGroup
id="formControlsPassword"
type="password"
label="Password"
name="password"
placeholder="Enter Password"
value={this.props.values[name]}
onChange={this.onChange}
help={this.state.errors.password}
/>
<FieldGroup
id="formControlsPasswordConfirmation"
type="password"
label="Password Confirmation"
name="passwordConfirmation"
placeholder="Enter Password"
value={this.props.values[name]}
onChange={this.onChange}
help={this.state.errors.passwordConfirmation}
/>
<FieldGroup
id="formControlsTimezone"
label="Time Zone"
name="timezone"
placeholder="Select Time Zone"
componentClass="select"
defaultValue="Select Your Timezone"
value={this.props.values[name]}
onChange={this.onChange}
help={this.state.errors.timezone}
>
<option value="Select Your Timezone">Select Your Timezone</option>
{
map(timezones, (key, value) =>
<option key={key} value={key}>{value}</option>)
}
</FieldGroup>
<FormGroup>
<Col smOffset={4} sm={8}>
<Checkbox>Remember me</Checkbox>
</Col>
</FormGroup>
<FormGroup>
<Col smOffset={4} sm={8}>
<Button type="submit" disabled={isLoading}
onClick={!isLoading ? isLoading : null}
>
{ isLoading ? 'Creating...' : 'Create New Account'}
</Button>
</Col>
</FormGroup>
{this.props.errorMessage && this.props.errorMessage.register &&
<div className="error-container">{this.props.errorMessage.register}</div>}
</Form>
//this.setState({ disabled: true });
//this.props.errorMessage.register == this.props = {errorMessage :{ register: ''}}
);
}
}
function mapStateToProps(state) {
return {
errorMessage: state.signup.error,
isLoading: state.signup.isLoading,
values: state.form.values
};
}
function mapDispatchToProps(dispatch) {
return {
onSave: (values) => dispatch(registerUser(values)),
onChange: (name, value) => dispatch(formUpdate(name, value))
};
}
export default connect(mapStateToProps, mapDispatchToProps)(SignupForm)
;
There is no need to use redux-form :-) You're on the right path and you're calling FORM_RESET action in the right place.
Couple of things:
are you sure you are importing formReset in actionRegister.js?
in reducerForm I would suggest to still return new state here:
case types.FORM_RESET:
return { ...INITIAL_STATE }; // or Object.assign({}, INITIAL_STATE)
And btw. why are you setting isLoading: true on success? I would suggest to create 3 actions instead of 2:
SAVE_USER_START (which you dispatch before sending a request),
set isLoading to true,
SAVE_USER_SUCCESS - set isLoading to false
SAVE_USER_FAILURE - set isLoading to false
I would suggest to look into redux-form library. It provides configuration option to clear fields after submit out of the box.