首页 > 解决方案 > 根据另一个字段值对一个字段使用 setFieldValue

问题描述

我正在使用 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 : ' ', ); }}

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

标签: javascriptreactjsformsformik

解决方案


我就是这样做的。

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;

计算字段.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


推荐阅读