Home > Blockchain >  onKeyDown and onChange with React and TypeScript
onKeyDown and onChange with React and TypeScript

Time:02-01

I am trying to assing an onChange and onKeyDown to an Input component with TypeScript and this is getting out of hand.

I have this Input component:

import React, { ChangeEvent, KeyboardEvent } from 'react'

import { InputStyle } from './Input-style'

type InputProps = {
  name: string
  value: string | number
  type?: string
  placeholder?: string
  onBlur?: () => void
  onKeyDown?: (e: KeyboardEvent) => void
  onChange?: (e: ChangeEvent<HTMLInputElement>) => void
}

export const Input = (props: InputProps) => (
  <InputStyle
    type={props.type ? props.type : 'text'}
    name={props.name}
    id={props.name}
    placeholder={props.placeholder}
    value={props.value}
    onKeyDown={props.onKeyDown}
    onChange={props.onChange}
    onBlur={props.onBlur}
  />
)

Then I am using the component to do two things, validate that the keypress entered is a number and then add the value, and what seems to be an easy task is just giving me all sorts of TypeScript errors about the type

import React, { KeyboardEvent, ChangeEvent } from 'react'

export const renderInput = () => {
  const [rate, setRate] = useState<number>(0)

   
  // I want to add the value only if is a number and between 0-1 no letters
  const addRate = (e: KeyboardEvent | ChangeEvent) => {

    const element = e.target as HTMLInputElement
    const value = element.value

    if ('key' in e) {
      const reg = /[0-9]/
      // If is not a letter
      if (reg.test(e.key)) {
        // Add the value but here now it breaks 
        setRate(isNaN(value) || value > 1 ? 0 : value)
      }
    }
  }

  return (
    <Input
     type='number'
     name='Conversion Rate'
     value={rate === 0 ? '' : rate}
     placeholder='Percentage Decimal number'
     onKeyDown={addRate}
     onChange={addRate}
   />
  )
}

But at this point TypeScript errors with

Argument of type 'string | 0' is not assignable to parameter of type 'SetStateAction'

I am really confused cause before trying to check for the keyDown it worked.

CodePudding user response:

I am guessing element.value is of type string.

You can parse it to number with parseInt(element.value) or element.value

That would be : const value = element.value

CodePudding user response:

onKeyDown dispatches value as character. Therefore Typescript conflict types.

You can convert in parseInt(value, 10).

You should note that field type number already accept only numbers and "e" of exponential.

CodePudding user response:

None of the answers worked for me, they might sound right in principal, but it just conflicted one against each other as per my example. I was heading to TypeScript hell, so I got out of it by using a regular text input and some regex:

const addRate = (val: string) => {
  // If it's a number and is higher than 1 exit
  if (!isNaN(parseInt(val)) && parseFloat(val) > 1) {
    return
  }

  // Regex to allow only decimal mumbers
  const reg = /^\d*(?:[.]\d*)?$/
  if (reg.test(val)) setRate(val)
}

<Input
  name='Conversion Rate'
  value={rate}
  placeholder='Decimal number - Optional'
  onChange={e => addRate(e.target.value)}
/>

No input type number, no keydown just regex

  •  Tags:  
  • Related