react-native-formik icon indicating copy to clipboard operation
react-native-formik copied to clipboard

withNextInputAutoFocus does not work with nested components

Open Gguigre opened this issue 5 years ago • 4 comments

Description

When using self-closing-tag components to generate text fields in a form, the withNextInputAutoFocusForm does not register the generated textInputs and the expected behaviour does not work : pressing "OK" with a textInput focused submits the entire form.

Steps to reproduce / example

const Form = withNextInputAutoFocusForm(View);

export class ReportForm extends PureComponent<PropsType, StateType> {
  renderForm = ({ values, handleSubmit }: { values: any, handleSubmit: Function }) => {
    return (
        <Form>
            <AircraftInformationSection />
      </Form>
    );
  };

  render() {
    return (
      <Formik
        // ...
        render={this.renderForm}
      />
    );
  }
}
export class AircraftInformationSection extends PureComponent<PropsType> {
  render() {
    return (
      <View>
        <TextInput
          name="aircraftInformationSectionType"
          // ...
        />
      </View>
    );
  }
}

In this case, getInputs does not see any children in the props of <AircraftInformationSection />

Ideas of technical solution

Create a Provider/Consumer system with textFields subscribing to the form. Add a prop to the form to specify the order of the fields to be focused.

Gguigre avatar Nov 28 '18 16:11 Gguigre

Hi @Gguigre, thanks for reporting!

In getInputs, withNextInputAutoFocusForm traverses the hierarchy of children of the wrapped component to find inputs. In your case, only one child is found, which is AircraftInformationSection, but not an input of course, and AircraftInformationSection itself does not have any children.

Would it be possible in your case to use withNextInputAutoFocusForm directly on AircraftInformationSection?

Almouro avatar Nov 28 '18 22:11 Almouro

Hi @Almouro, unfortunately, the <AircraftInformationSection /> component is not the only one inside the <Form> and they're other components that generate fields too.

Actually, the renderForm method is more like

renderForm = ({ values, handleSubmit }: { values: any, handleSubmit: Function }) => {
    return (
        <Form>
            <AircraftInformationSection />
            <FlightInformationSection />
            <EngineInformationSection />
      </Form>
    );
  };

So if I create one <Form /> for each section, the next won't handle passing between the different sections :(

Gguigre avatar Nov 29 '18 09:11 Gguigre

@Gguigre I believe you should also add that AircraftInformationSection has several inputs as children, not only one.

louiszawadzki avatar Nov 29 '18 11:11 louiszawadzki

Recently merge doesn't fix the issue. The thing is that getInputs recursive function doesn't get into components without children, so... if you have something like that:

const Address = () => {
  return <Box>
    <Input name={'address_line_1'}
    <Input name={'address_line_2'}
  </Box>
}

const RegistrationForm = () => {
  <Form>
    <Box>
      <Input name={'a'} />
      <Input name={'b'} />
      <Input name={'c'} />
      <Input name={'d'} />
    </Box>
    <Address />
  </Form>
}

where Form is hoc composed with withNextInputAutoFocus

it doesn't not get into Address component as it does not conform to this part

const getInputs = children =>
    //...
    if (child && child.props && child.props.children) { // <- well, this
      //...
    }
    //...
  }, []);

I'm trying to get the solution for that. I will leave PR for you @Almouro if I have any 🤷‍♂️

EDIT ok, I've found solution for that one. You can nest Forms, so basically this one below fixes the issue:

const Address = () => {
  return <Form>
    <Input name={'address_line_1'}
    <Input name={'address_line_2'}
  </Form>
}

const App = () => {
  <Form>
    //...
    <Address />
    //...
  </Form>
}

kacgrzes avatar Jan 14 '19 14:01 kacgrzes