web-dev-qa-db-ja.com

シンプルなFormikフォームをReduxストアに接続してアクションをディスパッチする方法は?

私はreact/reduxの初心者ですが、アプリの簡単なaddProductフォームを実現できます。今日、私はそれを Formik からこれに置き換えようとしました 基本的なデモ ですが、「ディスパッチ」関数をどこに配置すればよいかわかりません(どこにでも試しました)。

間違った方法で接続を使用する可能性がありますか?

新しいコンポーネントは Demo とまったく同じですが、EメールをproductName(およびその他の追加フィールド)に置き換えました。しかし、FormikからReduxストアに「値」を渡す方法を理解できません。

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;

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;

pSここに「formik」タグを追加するという評判がある場合は、実行してください。

5
Rustam Apaev

また、formikページで問題を開きました。そして、ある貢献者が私に答えをくれました。すべてはそのコードで動作します:

handleSubmit(values, { props, setSubmitting }) {
    props.dispatch(addProduct(values));
    setSubmitting(false);
  },
8
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

より高い変数または非同期関数を使用できます。より高い変数は少し不自由ですが機能しています。

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