2
votes

In my React Typescript app, there is a Formik form with fields that does not need to be populated with any values (i.e. the placeholder text is visible).

How can we achieve this?

Attempt 1:

In Formik's initialValues, I tried not defining any values whose form should be empty initially.

<Formik
    initialValues={{
        itemType: 'any',
    }}
    ...
>
interface Values {
    itemType: string;
    minPrice?: number;
    maxPrice?: number;
}

However, when a user types something into any of these forms, the browser JS console shows the warning:

index.js:1 Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components at input


Attempt 2:

Tried setting these values to null in Formik's initialValues prop,

<Formik
    initialValues={{
        itemType: 'any',
        minPrice: null,
        maxPrice: null,
    }}

    ...

but TypeScript throws an error:

Type 'string' is not assignable to type 'never'. TS2322

Type 'string' is not assignable to type 'never'.  TS2322

    66 |                 <Formik
    67 |                     initialValues={{
  > 68 |                         itemType: 'any',
       |                         ^
    69 |                         minPrice: null,

The React app does not even start!


Full Code

import { Button, Modal, Form, Row, Col } from 'react-bootstrap';
import { Formik, FormikHelpers } from 'formik';


interface Values {
    itemType?: string;
    minPrice?: number;
    maxPrice?: number;
}


export function FormModal({show, handleClose, updateFilter}: IModal): JSX.Element {
    return (
        <Modal show={show} onHide={handleClose}>
            <Modal.Body>
                <Formik
                    initialValues={{
                        itemType: 'any',
                        minPrice: null,
                        maxPrice: null,
                    }}
                    validationSchema={schema}
                    onSubmit={(
                        values: Values,
                    ) => {
                        updateFilter(values);
                        handleClose();
                    }}
                >
                    {( {values, errors, touched, handleChange, handleBlur, handleSubmit, isSubmitting, setFieldValue }) => (
                        <Form id="updateFilterForm" onSubmit={handleSubmit}>

                            <Form.Group as={Row} controlId="formItemType">
                                <Form.Label column sm="3">Item Type</Form.Label>
                                <Col sm="9">
                                    <Select 
                                        name="itemType" 
                                        options={itemTypeOptions} 
                                        onChange={option => setFieldValue("itemType", option!.value)} 
                                        onBlur={handleBlur} 
                                        values={values.itemType} 
                                    />
                                </Col>
                            </Form.Group>

                            <Form.Group as={Row} controlId="formPrice">
                                <Form.Label column sm="3">Price Range</Form.Label>
                                <Col sm="9">
                                    <Form.Row>
                                        <Col>
                                        <Form.Control 
                                            type="number" 
                                            name="minPrice" 
                                            onChange={handleChange} 
                                            onBlur={handleBlur} 
                                            value={values.minPrice} 
                                            placeholder="Min" 
                                        />
                                        </Col>
                                        <Col>
                                        <Form.Control 
                                            type="number" 
                                            name="maxPrice" 
                                            onChange={handleChange} 
                                            onBlur={handleBlur} 
                                            value={values.maxPrice} 
                                            placeholder="Max" 
                                        />
                                        </Col>
                                    </Form.Row>
                                </Col>
                            </Form.Group>

                        </Form>  
                    )}
                </Formik>
            </Modal.Body>
        </Modal>
    )
}
1
Have you imported the Select component?Anders Grandjean-Thomsen
@AndersGrandjean-Thomsen Yes, although not shown in the question.Nyxynyx

1 Answers

0
votes

As far as I can see it seems like you haven't defined your interface anywhere.

[ ... ]
const initialValues: Values = {
   itemType: 'any',
   minPrice: undefined,
   maxPrice: undefined,
};

<Formik initialValues={initialValues} {...}>

When working with interfaces remember when setting values to optional? use undefined and not null, if you must define a initial value.

Your app should pass typscript rules now and compile.