Write fewer React props passing to input element

April 27, 2021

programming
article cover

Presentational VS Container

We use two types of component as a convention of React.

Presentational components

  • are concerned how to display data (props)
  • have Markup and style
  • have no dependencies on Flux flow
  • don’t load data or mutate data
  • are usually stateless

Container components

  • are concerned how things work
  • have NO markup nor style
  • are connected with React flux flow
  • communicate with an external source
  • are usually stateful

This structure makes React more robust and simple, but we end up writing and passing so many props.

I’m gonna leave a note how to write fewer props.

Make a form

Let’s say we have to make a sign up form.

make a input.tsx,

import React from 'react'

interface Props {
  labelText: string
  type: string
  name: string
}

export const Input = (props: Props) => {
  const { labelText, type, name } = props

  return (
    <label>
      <span>{labelText}</span>
      <input type={type} name={name} />
    </label>
  )
}

then import it and render it inside form.tsx.

import React from 'react'
import { Input } from './input'

export const Form = () => {
  return (
    <div>
      <h1>Sign up form</h1>
      <Input labelText={'First name'} type={'text'} name={'firstName'} /> 
      <Input labelText={'Last name'} type={'text'} name={'lastName'} /> 
      <Input labelText={'email'} type={'email'} name={'email'} /> 
      <Input labelText={'password'} type={'password'} name={'password'} />
    </div>
  );
}

form

This is what we do usually, right?

More props

I wish we could finish by it, but we need to write more and more props in reality.

like this,

import React from 'react'

interface Props {
  labelText: string
  type: string
  name: string
  placeholder: string
  disabled: boolean
  required: boolean
  onChange: React.ChangeEventHandler<HTMLInputElement>
}

export const Input = (props: Props) => {
  const { 
    labelText, 
    type, 
    name, 
    placeholder,
    disabled,
    required,
    onChange
  } = props

  return (
    <label>
      <span>{labelText}</span>
      <input 
        type={type} 
        name={name} 
        placeholder={placeholder}
        disabled={disabled}
        required={required}
        onChange={onChange}
      />
    </label>
  )
}

I added some realistic props and it’s gonna be messier by time.

Let’s clean up and make it simple.

This time, I’m gonna use this one.

JSX.IntrinsicElements['input']

By this, You can get all attributes which input element has. So props definition becomes much better.

import React from 'react'

type InputProps = JSX.IntrinsicElements['input'] // new
type Props = InputProps & { labelText: string } // new

export const Input = (props: Props) => {
  const { 
    labelText, 
    type, 
    name, 
    placeholder,
    disabled,
    required,
    onChange
  } = props

  return (
    <label>
      <span>{labelText}</span>
      <input 
        type={type} 
        name={name} 
        placeholder={placeholder}
        disabled={disabled}
        required={required}
        onChange={onChange}
      />
    </label>
  )
}

Looks nice but not yet!
You can pass all props to <input> by spread syntax at once.

import React from 'react'

type InputProps = JSX.IntrinsicElements['input']
type Props = InputProps & { labelText: string }

export const Input = (props: Props) => {
  return (
    <label>
      <span>{props.labelText}</span>
      <input {...props} />
    </label>
  )
}

Almost done but there is just one more thing to do!

warning

<input> doesn’t have any attributes called labelText so React is complaining about it.
Let’s extract labelText from props.
You can use spread syntax again.

import React from 'react'

type InputProps = JSX.IntrinsicElements['input']
type Props = InputProps & { labelText: string }

export const Input = (props: Props) => {
  const { labelText, ...inputProps} = props
  
  return (
    <label>
      <span>{labelText}</span>
      <input {...inputProps} />
    </label>
  )
}

Ta-da! now it’s dead clean.
You can keep code tidy by using spread syntax even if you end up having more props.


Profile picture

Photographer / Web engineer working in Berlin.
A Japanese living with a Slovak wife and two German cats.