Connecting Redux Form with React Redux

nerdy_girl

Natalia

Posted on July 28, 2019

Connecting Redux Form with React Redux

Dealing with forms in React can be troublesome sometimes. You need to take care of proper state management, smooth user experience, simple form declarations, reusable components, etc. But the reason I moved to Redux Form was validation. I wanted to make the implementation of forms easier and quicker without adding a lot of code to my page's components. But I hit the wall when I tried to connect Redux Form with React Redux.

It wasn't the first time I was doing this so I did not expect any difficulties. I was wrong. With up to date dependencies I tried many different approaches while connecting reduxForm and connect() function. From putting one inside the other to connecting exported component with each function separately. Nothing was working properly. Regardless of what I tried, I ended up with this error message:

Uncaught Invariant Violation:
You must pass a component to the function returned by connect.
Instead received {"displayName":"ReduxForm",
"defaultProps": {destroyOnUnmount":true, "form":"loginForm", etc.}}
Enter fullscreen mode Exit fullscreen mode

I decided to look for help on the Internet. There was no straight answer helping me with what am I missing or how should I do it properly. And apparently, people still struggle with this problem. Checking StackOverflow and other forums resulted in finding only outdated working versions. Even official example from redux-form documentation wasn't working! I've decided to try baby steps method by connecting each part separately in different files. I ended up with an additional file container.tsx where I connected the component at a higher level. Let's see what happened.

First, let's connect a form component I created earlier with Redux Form:

import React from 'react'; 
import { Field, InjectedFormProps, reduxForm } from 'redux-form';

export interface IDispatchProps {
  //...
}

const LoginComponent = (props:IDispatchProps) => (
  <form>...</form>
);

export const LoginForm = reduxForm({
  form: 'loginForm',
})(LoginComponent);
Enter fullscreen mode Exit fullscreen mode

Next, let’s see how we can implement a container for that component:

import * as React from 'react';
import { connect } from 'react-redux';

import { LoginForm, IProps } from './LoginForm';
import actions from './actions';
import selector from './selector';

const LoginContainer = (props:IProps) =>
  <LoginForm {...props} />;

export default connect(selector, actions)(LoginContainer);
Enter fullscreen mode Exit fullscreen mode

What we are doing is we take the created LoginComponent function and wrap it with reduxForm. In container.tsx file LoginContainer function will pass our props to the imported component. In the end, we use connect() to create communication between our container and store props. The most tricky part starts if we want to add TypeScript to our form and do not use any at all! Leaving basic component's props will throw the error saying our props do not exist in this component. But we just passed it, right?

TS2559: Type '{ loginAction: () => any; }' has no properties in common with type
'IntrinsicAttributes & IntrinsicClassAttributes<FormInstance<{},
Partial<ConfigProps<{}, {}, string>>, string>> & Readonly
<Partial<ConfigProps<{}, {}, string>>> & Readonly<...>'.
Enter fullscreen mode Exit fullscreen mode

It took me at least an hour to figure it out and answer "why?". I decided to reach for help to the Internet again but the only answers I found weren't clear what was happening and where I should put my props. After a couple of tries, I finally found a solution which was sensible and I was happy with. First of all, in LoginForm.tsx file we need to create an interface IFormProps with the names of the fields that are in our form. Next we need to import type definition of InjectedFormProps from redux-form library and combine it with our props interface. InjectedFormProps accepts two parameters: FormProps = {} and P={}. The first one represents form data which will be put in the form and the second one is our component's props. Theoretically, you can leave both objects empty. But that's not why we are using TypeScript, right?

import React from 'react'; 
import { Field, InjectedFormProps, reduxForm } from 'redux-form';

interface IFormProps {
  username:string;
  password:string;
}

export interface IDispatchProps {
  //...
}

const LoginComponent =
(props:IDispatchProps & InjectedFormProps<IFormProps, IDispatchProps>) => (
  <form>
    <Field
      name="username"
      component={Input}
      type="text"
      label="Enter username"
    />
    <Field
      name="password"
      component={Input}
      type="password"
      label="Enter password"
    />
  </form>
);

export const LoginForm = reduxForm<IFormProps, IDispatchProps>({
  form: 'loginForm',
})(LoginComponent);
Enter fullscreen mode Exit fullscreen mode

To sum up, if you want to connect Redux Form with React Redux do yourself a favour and create another file which will be a bridge between those two libraries. And don't forget about InjectedFormProps to combine it with TypeScript. And if you want to see an example check out my working implementation: Redux Form with TypeScript. Good luck and see you next time! πŸ‘πŸ»

GitHub logo Nerdy-Girl / Redux-Forms-with-TypeScript

Connecting Redux Form with React Redux Example

CodeMeNatalie redux form

Redux Forms with TypeScript

This project is an example of working implementation of Redux Forms and TypeScript. Whole process is described in my article Connecting Redux Form and Connect.



Website β—¦ Blog

Quick start

  • Clone the repo: git clone https://github.com/CodeMeNatalie/Redux-Form-with-TypeScript.git
  • Install dependencies
  • Run the app npm start
  • Open http://localhost:3000 to view project in the browser.

coding doge

Enjoy πŸ’»






Important notice:
Article and example above were created with redux-form 8.2.2 and react-redux 6.0.1.

πŸ’– πŸ’ͺ πŸ™… 🚩
nerdy_girl
Natalia

Posted on July 28, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related