final-form / react-final-form-listeners

A collection of components to listen to 🏁 React Final Form fields
MIT License
94 stars 20 forks source link

How to avoid looping if two fields change each other's values? #9

Open ModPhoenix opened 5 years ago

ModPhoenix commented 5 years ago

I need to change the value of the give field if the value of the resave field changes and vice versa.

here is an example of my code:

import React from 'react';
import { Form, Field } from 'react-final-form';
import { OnChange } from 'react-final-form-listeners';

import RenderField from '../../components/Forms/FieldRender';
import FieldBtns from '../../components/Forms/FieldBtns';
// import AutoSave from '../../components/Forms/AutoSave';

const WhenFieldChanges = ({
  field,
  becomes,
  set,
  to,
}) => (
  <Field name={set} subscription={{}}>
    {(
      // No subscription. We only use Field to get to the change function
      { input: { onChange } },
    ) => (
      <OnChange name={field}>
        {() => {
          if (becomes) {
            onChange(to);
          }
        }}
      </OnChange>
    )}
  </Field>
);

let prevGiveCurrency;
let prevReceiveCurrency;

let prevGive;
let prevReceive;

const ExchangeForm = ({
  onSubmit,
  pairs,
  exchangeSetFrom,
  exchangeSetTo,
  price,
}) => (
  <div>
    <Form
      onSubmit={onSubmit}
      initialValues={{
        give: 0,
        receive: 0,
        giveCurrency: 'BTC',
        receiveCurrency: 'USD',
      }}
      // validate={(values) => {
      //   const errors = {};
      //   return errors;
      // }}
      render={({
        handleSubmit,
        submitting,
        values,
      }) => {
        prevGive = values.give;
        prevReceive = values.receive;

        if (prevGiveCurrency !== values.giveCurrency) {
          exchangeSetFrom(values.giveCurrency);
        }
        prevGiveCurrency = values.giveCurrency;

        if (prevReceiveCurrency !== values.receiveCurrency) {
          exchangeSetTo(values.receiveCurrency);
        }
        prevReceiveCurrency = values.receiveCurrency;

        return (
          <form onSubmit={handleSubmit}>
            {/* <AutoSave debounce={0} save={onSubmit} /> */}

            <WhenFieldChanges
              field="give"
              becomes={price}
              set="receive"
              to={values.give * price}
            />

            <WhenFieldChanges
              field="receive"
              becomes={price && values.receive !== prevReceive}
              set="give"
              to={values.receive * price}
            />

            <div className="form__field exchange__field">
              <label htmlFor="give" className="form__field-label">I give</label>
              <Field
                id="give"
                name="give"
                component={RenderField}
                type="text"
                placeholder={0}
              />
              <div className="form__field-select">
                <Field name="giveCurrency" component="select">
                  {pairs.map(pair => (
                    <option key={pair.fromSymbol} value={pair.fromSymbol}>{pair.fromSymbol}</option>
                  ))}
                </Field>
              </div>
            </div>
            <div className="form__field exchange__field">
              <label htmlFor="receive" className="form__field-label">I receive</label>
              <Field
                id="receive"
                name="receive"
                component={RenderField}
                type="text"
                placeholder={0}
              />
              <div className="form__field-select">
                <Field name="receiveCurrency" component="select">
                  {pairs.find(e => e.fromSymbol === values.giveCurrency)
                  && pairs.find(e => e.fromSymbol === values.giveCurrency).toSymbols.map(symbol => (
                    <option key={symbol} value={symbol}>{symbol}</option>
                  ))}
                </Field>
              </div>
            </div>
            <div className="form__btns exchange__btns">
              <FieldBtns
                type="submit"
                colorBtn="btn-success"
                sizeBtn="middle"
                classBtn="btn-login"
                translate="Exchange"
                disabled={submitting}
              />
            </div>
            <pre>{JSON.stringify(values, 0, 2)}</pre>
          </form>
        );
      }}
    />
  </div>
);

export default ExchangeForm;
bogdansoare commented 5 years ago

having the same issue