Migwell
Migwell

Reputation: 20107

Trigger event whenever validity changes in redux form

In my React + Redux + Redux-Form app, I need to enable/disable a "Next" button depending on the validity state of the form. This button is controlled by the parent component, so I can't just have <Button disabled={!props.valid}/>. Ideally redux-form would give me an event like onValidityChanged that I could listen for, and call the setCompleted() function passed down by the parent component whenever this happens. However such an event doesn't seem to exist. I also can't use the onChange hook, because at this point it won't have access to the props passed by the parent.

e.g.

function Parent(props){
    const [completed, setCompleted] = React.useState(false);

    return (
        <div>
            <Child setCompleted=setCompleted/>
            <button disabled={!completed}>Next</button>
        </div>
    );
}

const Child = reduxForm({form: 'form'})(props => {
    const {setCompleted} = props;

    // Call setCompleted once this form becomes valid
});

How can I run an event whenever the validity of the form changes, but still have access to props?

Upvotes: 0

Views: 475

Answers (1)

ManuKpL
ManuKpL

Reputation: 231

One simple way of doing so would be to read the current validity status as Redux-Form updates it in your redux state, using a selector. You can even use one provided by the redux-form package: isValid. Since you're using hooks, you can also use react-redux's useSelector hook (if you're using react-redux v7.1.0 or higher).

The result would be:

import { useSelector } from 'react-redux`;
import { reduxForm, isValid } from 'redux-form`;

const Child = reduxForm({form: 'form'})(props => {
    const { setCompleted } = props;
    const isFormValid = useSelector(state => isValid('form')(state));

    // Call setCompleted once this form becomes valid
    if (isFormValid) {
      setCompleted(true);
    }
});

Of course you may want to extract this selector in another file and memoize it.

You may also want to use this hook (or its mapStateToProps equivalent) directly inside the parent component to avoid using the useState hook in the first place.

Upvotes: 1

Related Questions