admin管理员组

文章数量:1208155

I'm new at react/redux, but can realize some simple addProduct form for my app. Today I tried to replace it with Formik from this Basic demo, but I cant't understand where should I place "dispatch" function (I tried it to everywhere).

May be I use connect in wrong way?

My new component is exactly like in Demo, except I replaced email with productName (and other additional fields). But I can't understand how to pass "values" from Formik to Redux store.

My old form component, without Formik, looks like this:

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;

I'm new at react/redux, but can realize some simple addProduct form for my app. Today I tried to replace it with Formik from this Basic demo, but I cant't understand where should I place "dispatch" function (I tried it to everywhere).

May be I use connect in wrong way?

My new component is exactly like in Demo, except I replaced email with productName (and other additional fields). But I can't understand how to pass "values" from Formik to Redux store.

My old form component, without Formik, looks like this:

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;

My new component with formik looks like this:

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;

p.s. If someone have reputation here to add tag "formik", please, do it.

Share Improve this question edited Mar 8, 2018 at 20:19 Peter Munnings 3,3291 gold badge32 silver badges43 bronze badges asked Nov 21, 2017 at 18:38 Rustam ApayRustam Apay 5911 gold badge4 silver badges18 bronze badges 2
  • 1 Dispatch is a method controlled by redux, the second parameter of the connect function is a method that maps the actions to the component props and THAT function is passed dispatch. See below for an example code – Joshua Underwood Commented Nov 21, 2017 at 18:50
  • 1 Note that I combined your export and connect lines into one statement, renaming the functional component to AddProduct. It appears you added the 0 for brevity's sake rather than trying to come up with another name for it. However, based on the code in the component this isn't necessary. If this helps, please mark the answer as correct. :) PS: Formik can't be added as tag because there is a maximum of five tags. – Joshua Underwood Commented Nov 21, 2017 at 18:56
Add a comment  | 

3 Answers 3

Reset to default 16

I also opened an issue on formik page. And there one of contributors gave me the answer. All works with that code:

handleSubmit(values, { props, setSubmitting }) {
    props.dispatch(addProduct(values));
    setSubmitting(false);
  },

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

/* AddProduct не совсем контейнер, он просто вызывает диспатч,
  ему не нужен стор, поэтому мы можем создать коннект коротким путем:
  AddProduct = connect()(AddProduct); */
const AddProduct = ({ addMyProduct }) => {
  let inputSKUNumber;
  let inputProductName;
  return (
    <div>
      <input
        ref={(node) => {
          inputSKUNumber = node;
        }}
        placeholder="SKU Number"
      />
      <input
        ref={(node) => {
          inputProductName = node;
        }}
        placeholder="Product name"
      />
      <button
        onClick={() => {
          addMyProduct({ SKUNumber: inputSKUNumber.value, name: inputProductName.value });
          inputSKUNumber.value = '';
          inputProductName.value = '';
        }}
      >
        Add Product
      </button>
    </div>
  );
};

const mapDispatchToProps = dispatch => ({
    addMyProduct: (params) => dispatch(addProduct(params))
});

export default connect(null, mapDispatchToProps)(AddProduct);

You can use a higher variable or async function. Higher variable is a little bit lame but working.

let setSubmittingHigher;
// Our inner form component. Will be wrapped with Formik({..})
const MyInnerForm = (props) => {enter code here

.
.
.

    handleSubmit(values, {props, setSubmitting}) {
        setSubmittingHigher = setSubmitting;

.
.
.

const mapStateToProps = (state) => {
    typeof setSubmittingHigher === 'function' && setSubmittingHigher(false);
    return {}
};

const mapDispatchToProps = dispatch => ({
    addMyProduct: (params) => dispatch(addProduct(params))
});

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

本文标签: javascriptHow to connect simple Formik form with Redux store and dispatch an actionStack Overflow