I'm trying to make an scalable Custom Form from an array of objects and a custom Input field, i'm working on a React-Typescript project
import React, { ChangeEvent } from "react"
import { InputField } from "./InputField"
interface FormItem {
key: string
fieldType: string
placeholder: string
value: string
errorMessage: string | null
validationMethod: (validateValue : string) => string | null
}
interface FormProps {
formProps : FormItem[]
}
export const CustomForm = ({formProps} : FormProps) => {
const [FORM, SETFORM] = React.useState(formProps)
const onFormChange = (event: ChangeEvent<HTMLInputElement>) => {
const target = event.currentTarget
const findChangedValue = FORM.find(fv => fv.key === target.name)
const validationText = findChangedValue?.validationMethod(target.value)!
const newForm = FORM.map(fv => {
if( target.value === fv.key ){
return {...fv, value: target.value, errorMessage: validationText}
}
return fv
})
SETFORM(newForm)
}
return (
<>
{FORM.map(( fv ) => {
<InputField
placeholderText={fv.placeholder}
name={fv.key}
inputType={fv.fieldType}
handleChange={onFormChange}/>
})}
</>
)
}
And I'm calling this component from a parent component sending this as a prop
interface FormProps {
key: string
fieldType: string
placeholder: string
value: string
errorMessage: string | null
validationMethod: ((validateValue : string) => string | null)
}
const FORM : FormProps[] = [
{ key: "email", placeholder:"Enter your email", fieldType: "text", value: "", errorMessage: "", validationMethod: validateEmail },
{ key: "password", placeholder:"Enter your password", fieldType: "text", value: "", errorMessage: "", validationMethod: validatePassword },
]
return (
<StyledForm enabledSubmit={enableSubmit}>
<h2>Login</h2>
<CustomForm formProps={FORM}/>
</StyledForm>
)
I tried console logging the props on CustomForm and the values are getting there just fine but the InputFields won't appear when i run the project, I also tried to console log the incoming props in the InputField component and they wont print, its like they get lost after passing them down in the map method, and I also tried wrapping the map method between form tags
CodePudding user response:
You're not returning anything from map
. You also need to use the key
prop and provide a unique key.
{FORM.map((fv) => (
<InputField
key={fv.key}
placeholderText={fv.placeholder}
name={fv.key}
inputType={fv.fieldType}
handleChange={onFormChange}
/>
))}
The curly brackets are changed to round brackets.
Round brackets (or no brackets) are an implicit return.
() => ("returning a value")
() => "returning a value"
Curly brackets execute the closure. ie. they require a return statement to return a value.
() => { "doing nothing" }
() => { return "returning a value" }
Interestingly, the only reason you don't see an error is because you have the map wrapped in a fragment, which I guess allows a void child node. If you change the fragment to a div, you'll see the error Type 'void[]' is not assignable to type 'ReactNode'.
Could I also suggest you clean up your type definitions?
Instead of three interfaces, you can just have one type:
export type FormItem = {
key: string
fieldType: string
placeholder: string
value: string
errorMessage: string | null
validationMethod: (validateValue : string) => string | null
}
const FORM : FormItem[] = [...]
export const CustomForm: FC<{ formProps: FormItem[] }> = ({ formProps }) => {...}