4

I am having some issues with setting the inital form field values using redux-form.

Here is the code I tried

import { Field, FieldArray, reduxForm, getFormValues, change } from 'redux-form'

const renderField = ({
  input,
  label,
  type,
  meta: { asyncValidating, touched, error }
}) => (
  <div>
    <label>{label}</label>
    <div className={asyncValidating ? 'async-validating' : ''}>
      <input {...input} type={type} placeholder={label}/>
      {touched && error && <span>{error}</span>}
    </div>
  </div>
)
class Profile extends Component {

  constructor(props) {
    super(props);
    this.state = {
      firstName: null,
      lastName: null,
    }
  }
  
  componentDidMount() {
    this.props.fetchProfile();    
  }

  async handleChange(e) {
    await this.setState({ 'initialValues': { [e.target.name] : e.target.value }});
    await this.setState({ [e.target.name] : e.target.value });
  }

onSubmit = (e) => {
    this.props.saveProfile({
      firstName: this.state.auth.firstName,
      lastName: this.state.auth.lastName,
    });
  }

  componentWillReceiveProps(nextProps) {
    this.setState({ 
      firstName : nextProps.initialValues.firstName,
      lastName : nextProps.initialValues.LastName,
     });

    this.setState({ 'initialValues': {
      firstName : nextProps.initialValues.firstName,
      lastName : nextProps.initialValues.LastName,
     }});
  }
render() {
    return (
      <>
        <form onSubmit={handleSubmit(this.onSubmit)}>
          <div>
          <Field
              name="firstName"
              type="text"
              component={renderField}
              label="firstName"
              onChange={this.handleChange.bind(this)}
            />
          </div>
          <div>
          <Field
              name="lastName"
              type="text"
              component={renderField}
              label="lastName"
              onChange={this.handleChange.bind(this)}
            />
          </div>
          <div>
            <button type="submit" disabled={pristine || submitting}>
              Update Info
            </button>
          </div>
    </form>
);
  }
}

Profile = reduxForm({
  form: 'Profile' ,
 // fields,
  validate,
  asyncValidate,
  enableReinitialize: true,
})(Profile);

function mapStateToProps(state, props){
  let firstName = '';
  let lastName = '';
  return {
    userData: state.auth.userData,
    initialValues:{
      firstName: state.auth.firstName,
      lastName: state.auth.lastName,
    }
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    fetchProfile: () => dispatch(auth.actions.fetchProfile()),
  }
} 

export default connect(mapStateToProps, mapDispatchToProps)(Profile);

But it is not setting value in field when load. field is just empty

Bhumi Shah
  • 9,323
  • 7
  • 63
  • 104
  • Getting API response and values are updating correctly in `componentWillReceiveProps`? Have you tried changing these values to `value={this.state.firstName ?? ''}` to `value={this.state.firstName || ''}`? – Prathap Reddy Jul 17 '20 at 19:05
  • @PrathapReddy: whenever i change value, handleChange is calling and key value is proper though state is not updating – Bhumi Shah Jul 20 '20 at 04:29
  • Did the answer helped you finally? If not, requesting you to post your solution to help others with similar issue. Thanks. @bhumi-shah – Prathap Reddy Jul 29 '20 at 06:53
  • 1
    @PrathapReddy Yes answer helped and that's why accepted!! You should add formprops comment into answer as it may help others to fix same issue – Bhumi Shah Jul 29 '20 at 08:56
  • I haven't received bounty for this hence I have [questioned](https://meta.stackoverflow.com/questions/399844/why-bounty-has-not-awarded-though-the-answer-is-accepted-by-author) it in `meta` to understand the process of `bounty`. Posted my previous comment to know if it actually helped you or not as per `answerers` comments in `meta` question. Anyway no offence. Just wanted to know why I missed `bounty`. Thanks for clarification. :-) – Prathap Reddy Jul 29 '20 at 09:00
  • @PrathapReddy I thought i accepted answer so you got bounty points. Let me check though – Bhumi Shah Jul 29 '20 at 10:12
  • Let it go this time. We can't do anything with the **existing process**. Please remember to award it manually (We will get 7 days to do this - 6 days of bounty period + 1 days grace period) rather than the **auto job** takes over it and **decide what to do** from next time. Anyways, the answer helped you with the `problem`. I am glad for that. I will get reputations daily upon my participation hence least bothered about it. I have **questioned on the bounty process/system awarding process** in `meta` discussion. – Prathap Reddy Jul 29 '20 at 10:24

1 Answers1

2

I guess Redux Form works little different.

You don't need to set explicit onChange handler or declare any state to hold form fields data in Redux Form. Update your code similar to below

import { Field, FieldArray, reduxForm, getFormValues, change } from 'redux-form'

const renderField = ({
  input,
  label,
  type,
  meta: { asyncValidating, touched, error }
}) => (
  <div>
    <label>{label}</label>
    <div className={asyncValidating ? 'async-validating' : ''}>
      <input {...input} type={type} placeholder={label}/>
      {touched && error && <span>{error}</span>}
    </div>
  </div>
)
class Profile extends Component {
  // No need constructor/to explicitly declare the state
  componentDidMount() {
    this.props.fetchProfile();    
  }

render() {
    const { handleSubmit, pristine, submitting} = props; // You can have custom handleSubmit too
    return (
      <>
        <form onSubmit={handleSubmit}>
          <div>
          <Field
              name="firstName"
              type="text"
              component={renderField}
              label="firstName"
            />
          </div>
          <div>
          <Field
              name="lastName"
              type="text"
              component={renderField}
              label="lastName"
            />
          </div>
          <div>
            <button type="submit" disabled={pristine || submitting}>
              Update Info
            </button>
          </div>
    </form>
);
  }
}

Profile = reduxForm({
  form: 'Profile' ,
 // fields,
  validate,
  asyncValidate,
  enableReinitialize: true,
})(Profile);

function mapStateToProps(state, props) {
  return {
    userData: state.auth.userData,
    initialValues:{ // These are the initial values. You can give any name here for testing to verify the ReduxForm working
      firstName: state.auth.firstName,
      lastName: state.auth.lastName,
    }
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    fetchProfile: () => dispatch(auth.actions.fetchProfile()),
  }
} 

export default connect(mapStateToProps, mapDispatchToProps)(Profile);

The example in question and the answer would definitely help you to understand things better.

Prathap Reddy
  • 1,688
  • 2
  • 6
  • 18
  • This is still creating issue. – Bhumi Shah Jul 20 '20 at 06:52
  • Are you getting any issues in the `console` while `handleChange` is execute on typing? – Prathap Reddy Jul 20 '20 at 06:55
  • updated componentWillReceiveProps and set handleChange to async. See updated code – Bhumi Shah Jul 20 '20 at 06:55
  • When I click on submit, it gets previous value instead of new value – Bhumi Shah Jul 20 '20 at 06:57
  • No need to change `handleChange` async. Can you just try with the 2 changes. 1) Constructor binding as suggested in answer. 2) simple mapping in onChange like this `onChange={this.handleChange}` – Prathap Reddy Jul 20 '20 at 06:59
  • If i remove async from handleChange, it is not updating state and componentWillReceiveProps return old value – Bhumi Shah Jul 20 '20 at 07:08
  • Do you think, there is an issue in initialValues – Bhumi Shah Jul 20 '20 at 07:37
  • Nope. `initialValues` thing looks good to me. Let me check the `Redux Form` docs which I didn't use much. Will update you if I found something helpful. – Prathap Reddy Jul 20 '20 at 07:46
  • is there any issue in validate? because it is not stopping form to submit – Bhumi Shah Jul 20 '20 at 08:38
  • You need to pass `validate` function which perform validations to stop form `submit`. This [redux async form change docs](https://redux-form.com/8.3.0/examples/asyncchangevalidation) has detailed explanation on how async form change works. BTW, updated my answer. Hope it helps you. – Prathap Reddy Jul 20 '20 at 09:18
  • Okay but I am still getting issue in passing value from state. mapStateToProps is gettiing older one – Bhumi Shah Jul 20 '20 at 10:21
  • Able to render form with initial values just by hardcoding as suggested in answer instead of reading from `state.auth`? And able get anything help from docs [using state rendering](https://redux-form.com/8.3.0/examples/initializefromstate)?? – Prathap Reddy Jul 20 '20 at 10:27
  • hardcoded value doesn't work with redux-form – Bhumi Shah Jul 20 '20 at 10:49
  • I mean having `initialValues` - firstName: 'Test', lastName: 'User' etc.. in `mapStateToProps` is showing those custom values in UI? – Prathap Reddy Jul 20 '20 at 10:55
  • Yes it is showing in ui but when handleChange on onSubmit, I am not getting updated value – Bhumi Shah Jul 20 '20 at 11:04
  • As suggested in code snippet in my answer, the on change/`handleChange` is not required for redux form. For `onSubmit` you need to use the redux-form `props` handleSubmit as per the example question I have mentioned in my answer. You can log the updated form values on custom `handleSubmit` as per the link in my answer. – Prathap Reddy Jul 20 '20 at 11:12
  • I don't have much knowledge on `ReduxForm`. Suggested solutions based on my `React/Redux` knowledge. Please post your working answer once you are able to get the desired behaviour. Thanks – Prathap Reddy Jul 20 '20 at 11:16
  • I am using handleSubmit, see updated code in question. Though same issue – Bhumi Shah Jul 20 '20 at 11:18
  • Tried removing `onChange` prop on `Field` component? Able to the name changes in your `onSubmit` method upon submit click? `oSubmit = (formProps) => { console.log(formProps); }`!? – Prathap Reddy Jul 20 '20 at 11:21