将setFieldValue用于一个字段,基于另一个字段的值

时间:2019-09-24 08:32:28

标签: javascript reactjs forms formik

我正在使用formik react库,并尝试基于另一个的onChange事件更新2个字段。例如,

price = quantity * totalPrice

price :
onChange={() => {setFieldValue('quantity',values.quantity? values.price / values.totalPrice:values.quantity, );
setFieldValue('totalPrice',values.totalPrice? values.price * values.quantity: values.totalPrice,);}}

quantity :
onChange={(value, e) => { this.disableFiled(value, e); setFieldValue('totalPrice',values.price ? values.price * values.totalPrice : ' ',);}}

totalPrice:
onChange={(value, e) => { this.disableFiled(value, e);setFieldValue('quantity',values.price ? values.totalPrice / price : ' ', ); }}

当数量具有价值时,总价将被禁用,反之亦然。但是它不能正确计算其他字段

2 个答案:

答案 0 :(得分:5)

这就是我的方法。

App.js文件:

import React from "react";
import "./styles.css";
import { Formik } from "formik";
import * as Yup from "yup";
import CalculatedField from "./CalculatedField";

const App = () => (
  <div className="app">
    <Formik
      initialValues={{ price: "", quantity: "", totalPrice: "" }}
      onSubmit={async values => {
        await new Promise(resolve => setTimeout(resolve, 500));
        alert(JSON.stringify(values, null, 2));
      }}
      validationSchema={Yup.object().shape({
        price: Yup.number("It's a number").required("Required"),
        quantity: Yup.number("It's a number").required("Required"),
        totalPrice: Yup.number("It's a number").required("Required")
      })}
    >
      {props => {
        const {
          values,
          touched,
          errors,
          isSubmitting,
          handleChange,
          handleBlur,
          handleSubmit,
          setFieldValue
        } = props;
        return (
          <form onSubmit={handleSubmit}>
            <div className="input-row">
              <label htmlFor="quantity" style={{ display: "block" }}>
                Quantity
              </label>
              <input
                id="quantity"
                name="quantity"
                placeholder="Enter quantity"
                type="number"
                value={values.quantity}
                onChange={handleChange}
                onBlur={handleBlur}
                className={
                  errors.quantity && touched.quantity
                    ? "text-input error"
                    : "text-input"
                }
              />
              {errors.quantity && touched.quantity && (
                <div className="input-feedback">{errors.quantity}</div>
              )}
            </div>
            <div className="input-row">
              <label htmlFor="price" style={{ display: "block" }}>
                Price
              </label>
              <input
                id="price"
                name="price"
                placeholder="Enter your price"
                type="number"
                value={values.price}
                onChange={handleChange}
                onBlur={handleBlur}
                className={
                  errors.price && touched.price
                    ? "text-input error"
                    : "text-input"
                }
              />
              {errors.price && touched.price && (
                <div className="input-feedback">{errors.price}</div>
              )}
            </div>

            <div className="input-row">
              <label htmlFor="totalPrice" style={{ display: "block" }}>
                Total Price
              </label>
              <CalculatedField
                id="totalPrice"
                type="number"
                name="totalPrice"
                value={values.totalPrice}
                values={values}
                setFieldValue={setFieldValue}
                onChange={handleChange}
                onBlur={handleBlur}
                className={
                  errors.totalPrice && touched.totalPrice
                    ? "text-input error"
                    : "text-input"
                }
              />
              {errors.totalPrice && touched.totalPrice && (
                <div className="input-feedback">{errors.totalPrice}</div>
              )}
            </div>

            <div className="input-row">
              <button type="submit" disabled={isSubmitting}>
                Submit
              </button>
            </div>
          </form>
        );
      }}
    </Formik>
  </div>
);
export default App;

CalculatedField.js

import React, { useEffect } from "react";

const CalculatedField = props => {
  useEffect(() => {
    var val = 0;
    if (props.values.price && props.values.quantity) {
      val = props.values.price * props.values.quantity;
    }
    props.setFieldValue("totalPrice", val);
  }, [props.values]);

  return (
    <input
      id="totalPrice"
      type="number"
      name="totalPrice"
      value={props.values.totalPrice}
    />
  );
};

export default CalculatedField;

这基本上是通过在CalculatedField组件的useEffect挂钩内调用setFieldValue方法来实现的。请记住,useEffect将监视值的更改,并在修改后运行setFieldValue方法。

请遵循CodeSandbox演示。 https://codesandbox.io/s/affectionate-mirzakhani-who30?file=/src/App.js

答案 1 :(得分:1)

检查一下可能有帮助:

https://github.com/jaredpalmer/formik/issues/1840

您必须致电handleChange(e)现场更改!