question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to use Formik basic component with React-Redux connect function?

See original GitHub issue

Hi, thanks for great plugin! I have the component AddProduct, wich works, and adds product to redux store. It looks like this (without formik):

import React from 'react';
import { connect } from 'react-redux';
import { addProduct } from '../actions';

const AddProduct0 = ({ dispatch }) => {
  let inputSKUNumber;
  let inputProductName;
  return (
    <div>
      <input
        ref={(node) => {
          inputSKUNumber = node;
        }}
        placeholder="SKU Number"
      />
      <input
        ref={(node) => {
          inputProductName = node;
        }}
        placeholder="Product name"
      />
      <button
        onClick={() => {
          dispatch(addProduct({ SKUNumber: inputSKUNumber.value, name: inputProductName.value }));
          inputSKUNumber.value = '';
          inputProductName.value = '';
        }}
      >
        Add Product
      </button>
    </div>
  );
};
const AddProduct = connect()(AddProduct0);

export default AddProduct;

Today I tried to rewtrite this component using Formik (in full version there is 7 fields with validation, but for more clear example I explain here only 2 fields, like in old version). Validation works, and I see “variables” and other props, when I change fields. I liked Formik. That how it looks my form with it:

screenshot from 2017-11-22 01-56-14

But I can’t dispatch the action to the redux store. Can somebody answer, how to use connect in right way with HOC (container component) EnhancedForm, and presentational component MyInnerForm. It’s how looks my new code with Formik:

import React from 'react';
import { connect } from 'react-redux';
import { withFormik } from 'formik';
import Yup from 'yup';
import { addProduct } from '../actions';
import './helper.css';

// Our inner form component. Will be wrapped with Formik({..})
const MyInnerForm = (props) => {
  const {
    values,
    touched,
    errors,
    dirty,
    isSubmitting,
    handleChange,
    handleBlur,
    handleSubmit,
    handleReset,
  } = props;
  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="SKUNumber">SKU Number</label>
      <input
        id="SKUNumber"
        placeholder="SKU Number"
        type="number"
        value={values.SKUNumber}
        onChange={handleChange}
        onBlur={handleBlur}
        className={errors.SKUNumber && touched.SKUNumber ? 'text-input error' : 'text-input'}
      />
      <div className="input-feedback">{touched.SKUNumber ? errors.SKUNumber : ''}</div>

      <label htmlFor="productName">Product Name</label>
      <input
        id="productName"
        placeholder="Product Name"
        type="text"
        value={values.productName}
        onChange={handleChange}
        onBlur={handleBlur}
        className={errors.productName && touched.productName ? 'text-input error' : 'text-input'}
      />
      <div className="input-feedback">{touched.productName ? errors.productName : ''}</div>


      <button
        type="button"
        className="outline"
        onClick={handleReset}
        disabled={!dirty || isSubmitting}
      >
        Reset
      </button>
      <button type="submit" disabled={isSubmitting}>
        Submit
      </button>

      <DisplayFormikState {...props} />
    </form>
  );
};

const EnhancedForm = withFormik({
  mapPropsToValues: () => ({
    SKUNumber: 12345678,
    productName: 'Default Product',
  }),

  validationSchema: Yup.object().shape({
    SKUNumber: Yup.number()
      .max(99999999, 'SKU Number must be less than 8 digits')
      .required('SKU Number is required!'),

    productName: Yup.string()
      .min(5, 'Product name must be longer than 5 symbols')
      .max(50, 'Product name must be shorter than 50 symbols')
      .required('Product name is required!'),

  handleSubmit: (values, { setSubmitting }) => {
    setTimeout(() => {
      alert(JSON.stringify(values, null, 2));
      setSubmitting(false);
    }, 1000);
    // dispatch(addProduct(values));
  },
  displayName: 'BasicForm', // helps with React DevTools
})(MyInnerForm);

export const DisplayFormikState = props => (
  <div style={{ margin: '1rem 0' }}>
    <h3 style={{ fontFamily: 'monospace' }} />
    <pre
      style={{
        background: '#f6f8fa',
        fontSize: '.65rem',
        padding: '.5rem',
      }}
    >
      <strong>props</strong> = {JSON.stringify(props, null, 2)}
    </pre>
  </div>
);

const AddProduct = connect()(EnhancedForm);

export default AddProduct;

I used this “Basic example” to make my first step in formik. Also I have written the same question on Stackowerflow.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:3
  • Comments:15

github_iconTop GitHub Comments

19reactions
alitinkercommented, Jul 30, 2018

@ianemv Thank you. I had to set mine up a little differently because I’m using bindActionCreators and used the input primitives approach but the concept is mostly the same. Seems to be working now. Here for anyone who finds this useful:

import React from 'react';
import { withFormik } from 'formik';
import * as Yup from 'yup';
import * as Fields from '../../shared/layout/components/forms-component';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { actionCreators } from '../../shared/auth/store/auth-store';

class LoginForm extends React.Component {
    render() {
        const {
            values,
            touched,
            errors,
            dirty,
            handleChange,
            handleBlur,
            handleSubmit,
            handleReset,
            isSubmitting,
        } = this.props;
        return (
            <div className="forms-styles">
                <form onSubmit={handleSubmit}>
                    <div>
                        <div className="single-row">
                            <Fields.TextInput
                                id="userId"
                                type="text"
                                label="User ID"
                                placeholder="User ID"
                                error={touched.userId && errors.userId}
                                value={values.userId}
                                onChange={handleChange}
                                onBlur={handleBlur}
                            />
                        </div>
                        <div className="single-row">
                            <Fields.TextInput
                                id="userPassword"
                                type="password"
                                label="Password"
                                placeholder="Password"
                                error={touched.userPassword && errors.userPassword}
                                value={values.userPassword}
                                onChange={handleChange}
                                onBlur={handleBlur}
                            />
                        </div>
                        <div className="single-row">
                            <button className="button secondary" type="submit" disabled={isSubmitting}>
                                Login
                        </button>
                        </div>
                    </div>
                </form>
            </div>
        );
    }
};

const formikEnhancer = withFormik({
    validationSchema: Yup.object().shape({
        userId: Yup.string()
            .required('User ID is required.'),
        userPassword: Yup.string()
            .required('Password is required.')
    }),
    mapPropsToValues: () => ({
        userId: 'test',
        userPassword: 'test'
    }),
    handleSubmit: (payload, { props, setSubmitting }) => {
        props.loginUser(payload);
        setSubmitting(false);
    },
    displayName: 'LoginForm',
})(LoginForm);

const Login = connect(
    state => state.login,
    dispatch => bindActionCreators(actionCreators, dispatch)
)(formikEnhancer)

export default Login;
11reactions
sinkalex31commented, Nov 22, 2017

Dispatch must be already accessible form your props. And props are passed to submit function.

Simple example:

const handleSubmit = (values, { props }) => props.dispatch(someAction(values));

@connect(...)
@withFormik(
   handleSubmit,
   ...,
)
class FormPresentation extends Component {
   render() {
      const { handleSubmit, ... } = this.props;

      return() {
          <form onSubmit={handleSubmit}>
              /* fields */
          </form>   
      }
   }
}

Now you can use dispatch from props, the same can be accomplished without class, this example with decorators is just more readable

Read more comments on GitHub >

github_iconTop Results From Across the Web

Integrating Formik and Redux: complex forms made easy
Handling forms in React is a tedious task to do. In this post you will see how to integrate Redux and Formik to...
Read more >
How to connect simple Formik form with Redux store and ...
1. Dispatch is a method controlled by redux, the second parameter of the connect function is a method that maps the actions to...
Read more >
React Formik with Redux #19 - YouTube
React JS Full Course | 30 Hours Training Full Playlist for React JS Full Coursehttps://github.com/tkssharma/ react -forms- formik ...
Read more >
withFormik() | Formik
Create a higher-order React component class that passes props and form handlers (the " FormikBag ") into your component derived from supplied options....
Read more >
Building forms with Formik in React - LogRocket Blog
Building forms with React involves setting up state as the container for user data and props as the means to control how state...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found