Search code examples
reactjstypescriptformikreact-typescripttsx

React Formik Warning: A component is changing an uncontrolled input to be controlled


I am creating a fairly simple todo application in React with TypeScript.

For the form I am using Formik.

The error I get is this when I add value into the input field

3973 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

From my previous googling on the topic I learned that the problem most likely is because of the formik InitialValues

Let me show you some code

export interface textFieldProps {
    field: string;
    displayName: string;
}


import { ErrorMessage, Field } from "formik";
import { textFieldProps } from "../interfaces/UtilsProps.interface";

export const TextField = (props: textFieldProps) => {
  return (
    <div className="mb-3">
      <label htmlFor={props.field}>{props.displayName}</label>
      <Field name={props.field} id={props.field} className="form-control" />
      <ErrorMessage name={props.field}>
        {(msg) => <div className="text-danger">{msg}</div>}
      </ErrorMessage>
    </div>
  );
};

Also this

export interface createTodoModel {
    todo: string;
    isComplete: boolean;
}

export interface TodoFormProps {
    model: createTodoModel;
    onSubmit(values: createTodoModel, action: FormikHelpers<createTodoModel>): void;
}

import { Form, Formik } from "formik"
import { TodoFormProps } from "../interfaces/TodoProps.interface"
import * as yup from 'yup'
import { TextField } from "../Utils/TextField"
import Button from "../Utils/Button"

export const TodoForm = (props: TodoFormProps) => {
    return(
        <Formik initialValues={props.model}
        onSubmit={props.onSubmit}
        validationSchema={yup.object({
            name: yup.string().max(50, 'max length is 50 characters').required('You must add an todo').firstLetterUpperCase()
        })}
        >
            {(FormikProps) => (
                <Form>
                    <TextField field='name' displayName='What do you need done?' />
                    <Button children='Add your todo' className='btn btn-outline-primary' disabled={FormikProps.isSubmitting} />
                </Form>
            )}

        </Formik>
    )
}

And this

import { TodoForm } from "../components/Todos/TodoForm"

export const TodoView = () => {
    return(
        <article>
            <TodoForm model={{todo: "", isComplete: false}}
            onSubmit={async value => {
                await new Promise(r => setTimeout(r, 1000));
                console.log(value)
            }}/>
        </article>
    )
}

I however, did not have any luck in my googling.

Would you know a solution to this problem? If so, I would much appreciate it!

Thanks!


Solution

  • I Changed this

    export interface createTodoModel {
        todo: string;
        isComplete: boolean;
    }
    

    into this

    export interface createTodoModel {
            name: string;
            isComplete: boolean;
        }
    

    and now it works