web-dev-qa-db-fra.com

Comment connecter un formulaire Formik simple au magasin Redux et envoyer une action?

Je suis nouveau sur react/redux, mais je peux réaliser une forme addProduct simple pour mon application. Aujourd'hui, j'ai essayé de le remplacer par Formik de cette Démo de base , mais je ne comprends pas où placer la fonction "dispatch" (je l'ai essayée partout).

Peut-être que je me connecte mal?

Mon nouveau composant est exactement comme dans Demo , sauf que j'ai remplacé l'email par productName (et d'autres champs supplémentaires). Mais je ne comprends pas comment passer des "valeurs" de Formik à Redux Store.

Mon ancien composant de formulaire, sans Formik, ressemble à ceci:

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;

Mon nouveau composant avec formik ressemble à ceci:

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. Si quelqu'un a la réputation d'ajouter la balise "formik" ici, faites-le.

3
Rustam Apaev

J'ai aussi ouvert un numéro sur la page formik. Et là l'un des contributeurs m'a donné la réponse. Tout fonctionne avec ce code: 

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

7
Rustam Apaev

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);

0
Joshua Underwood

Vous pouvez utiliser une variable plus élevée ou une fonction asynchrone. Une variable plus élevée est un peu boiteuse mais fonctionne.

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);
0
goker.cebeci