3

I'm trying to use React-final-form with a DropDown in a Child Component. Can't get this to work.

All of my text fields are already in a Child Component and this works like a charm. The field in the parent looks like this:

<Field
    name="lastName"
    placeholder="Last Name"
    validate={required}
>
    {({input, meta, placeholder}) => (
        <MyField meta={meta} input={input} placeholder={placeholder}/>
    )}
</Field>

The Child Component looks like this:

export const MyField = (props) => {
    return (
        <Form.Field className={props.meta.active ? 'active' : ''}>
            <Label>{props.label ? props.label : props.placeholder}</Label>
            <Form.Input
                {...props.input}
                placeholder={props.placeholder}
                className={(props.meta.error && props.meta.touched ? 'error' : '')}
            />
        </Form.Field>
    )
};

The "Form.Field" and "Label" are coming from semantic-ui-react

But now I want to do the same with a DropDown. The standard DropDown, taken from an example on the React-Final-Form site, looks like this:

<Field name="toppingsA" component="select">
    <option value="chicken">Chicken</option>
    <option value="ham">Ham</option>
    <option value="mushrooms">Mushrooms</option>
    <option value="cheese">Cheese</option>
    <option value="tuna">Tuna</option>
    <option value="pineapple">Pineapple</option>
</Field>

And it works in a sense that I'm getting the value in my react-final-form values onSubmit. then I'm trying to offload the Dropdown itself to the Child Component (with the intention to use the semantic-ui-react version of a Dropdown, but first things first and get the Dropdown to work :-) )

Parent Component:

const eatOptions = [
    {key: 'c', text: 'Chicken', value: 'chicken'},
    {key: 'h', text: 'Ham', value: 'ham'},
    {key: 'm', text: 'Mushrooms', value: 'mushrooms'},
    {key: 't', text: 'Tuna', value: 'tuna'}
];

// And in the Form:
<Field name="toppingsB" component="select" options={eatOptions}>
    { ({input,  meta, options}) => {
        return (
            <Opts options={options} name={input.name}/>
        )
    }}
</Field>

And in the Child Component:

export const Opts = (props) => {
    return (
        <select name={props.name}>
            {props.options.map((x) => {
                return (
                    <option key={x.key} value={x.value}>{x.text}</option>
                )
            })}
        </select>
    )
};

Result is that the HTML looks the same (which does not say that much I guess), ToppingsA is picked up in the values (on onSubmit) and ToppingsB is not. I can't figure out what am I missing here and your help would be very much appreciated.

Thanks in advance, Bert

BertC
  • 2,243
  • 26
  • 33

2 Answers2

5

If you are using render-props for toppingsB then the Field component prop should not be type "select" as the children of Field will be a function and not multiple tags.

It also looks like you are not letting your form know of any changes that occur inside the child component. Try passing the Opts component an onChange function as a prop:

 <Opts 
    options={options}
    name={input.name}
    onChange={ (value:string) => input.onChange(value)}
  />

S. Taylor
  • 71
  • 2
4

@S.Taylor, Thanks for your help!! It works.

As a reference the working code:

The Field in Parent Component:

<Field name="toppingsB" options={eatOptions} >
    { ({input,  meta, options}) => {
        return (
            <Opts
                options={options}
                name={input.name}
                onChange={ (value) => input.onChange(value)}
            />
        )
    }}
</Field>

And the code in the Child Component:

export const Opts = (props) => {
    return (
        <select name={props.name} onChange={props.onChange}>
            {props.options.map((x) => {
                return (
                    <option key={x.key} value={x.value}>{x.text}</option>
                )
            })}
        </select>
    )
};
BertC
  • 2,243
  • 26
  • 33