Using Redux-Forms with Connect and Typescript

1.2k views Asked by At

I have a saveMember(member: Member) method in my Action Creator. I should pass a Member type object to that method. I was able to do this with a normal HTML form. Then I tried to do it with redux-form library.

I don't understand how to use both Connect and Redux Forms in the same component. When using the normal HTML forms, I was able to define a onSubmit handler method inside the MemberForm component itself and get the values from the inputs and call the saveMember action. But I don't understand how to do it now.

Referring to some code on github I tried the following code:

import * as React from 'react';
import { Link, RouteComponentProps } from 'react-router-dom';
import { connect } from 'react-redux';
import { ApplicationState } from '../store';
import * as MembersState from '../store/Members';
import * as ReactDOM from 'react-dom';
import { Member } from "../store/Members";
import { reduxForm, Field, FormErrors, FormProps } from 'redux-form';

interface FormData {
    name?: string;
    age?: string;
}

const validate = (values: Readonly<FormData>): FormErrors<FormData> => { 
    const errors: FormErrors<FormData> = {};

    if(values.name === undefined) {
        errors.name = 'name needed';
    }

    if(values.age === undefined) {
        errors.age = 'age needed';
    }

    return errors;
};


// At runtime, Redux will merge together...
type MemberFormProps =
    MembersState.MembersState        // ... state we've requested from the Redux store
    & typeof MembersState.actionCreators      // ... plus action creators we've requested
    & RouteComponentProps<{}>; // ... plus incoming routing parameters

class MemberForm extends React.Component<MemberFormProps, {}> {


    componentWillMount() {
        // This method runs when the component is first added to the page
        this.props.getMembers();
    }

    public render() {
        return <div>
            <h1>Members</h1>
            {this.renderForecastsTable()}
            <hr/>
            {this.renderForm()}
        </div>;
    }

    private renderForecastsTable() {
        return <table className='table'>
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Name</th>
                    <th>Age</th>
                </tr>
            </thead>
            <tbody>
                {this.props.members.map(member =>
                    <tr key={member.id}>
                        <td>{member.id}</td>
                        <td>{member.name}</td>
                        <td>{member.age}</td>
                    </tr>
                )}
            </tbody>
        </table>;
    }

    private renderForm() {


        return <form className="htmlForm-horizontal">
                    <div className="form-group">
                        <label className="control-label col-sm-2" htmlFor="name">Name:</label>
                        <Field placeholder="First name" name="name" component="input" />
                    </div>
                    <br/><br/>
                    <div className="form-group">
                        <label className="control-label col-sm-2" htmlFor="age">Age:</label>
                        <Field placeholder="Age" name="age" component="input" />
                    </div>
                    <br/><br/>
                    <div className="form-group">        
                        <div className="col-sm-offset-2 col-sm-10">
                            <button type="submit" className="btn btn-default">Submit</button>
                        </div>
                    </div>
                </form>;
    }
}

let MemberFormConnect = connect(
    (state: ApplicationState) => state.members, // Selects which state properties are merged into the component's props
    MembersState.actionCreators                 // Selects which action creators are merged into the component's props
)
(MemberForm) as typeof MemberForm;

export default reduxForm<MemberFormProps, MemberForm>({
    form: 'SelectionWithForm',
    validate: validate,
    onSubmit: (values, dispatch, props) => {
        console.log('submit is being handled...');
        let member: Member = { name: values.name, age: parseInt(values.age) }; 
        props.saveMember(member);
    }
})(MemberFormConnect);

When I use this code I get compilations errors in every line inside export default reduxForm.

ERROR in [at-loader] ./ClientApp/components/MemberForm.tsx:103:55 
    TS2345: Argument of type '{ form: string; validate: (values: Readonly<FormData>) => FormErrors<FormData, void>; onSubmit: (...' is not assignable to parameter of type 'Partial<ConfigProps<MemberFormProps, MemberForm>>'.
  Types of property 'validate' are incompatible.
    Type '(values: Readonly<FormData>) => FormErrors<FormData, void>' is not assignable to type '((values: MemberFormProps, props: MemberForm & InjectedFormProps<MemberFormProps, MemberForm>) =>...'.
      Type '(values: Readonly<FormData>) => FormErrors<FormData, void>' is not assignable to type '(values: MemberFormProps, props: MemberForm & InjectedFormProps<MemberFormProps, MemberForm>) => ...'.
        Type 'FormErrors<FormData, void>' has no properties in common with type 'FormErrors<MemberFormProps, void>'.

I don't have experience with react and redux, please help me.

0

There are 0 answers