Skip to content

Instantly share code, notes, and snippets.

@Xananax
Created February 5, 2018 20:11
Show Gist options
  • Save Xananax/de84477004049c261d4b8c65a54e3ccf to your computer and use it in GitHub Desktop.
Save Xananax/de84477004049c261d4b8c65a54e3ccf to your computer and use it in GitHub Desktop.
Basic React Input
/**
* Tired of re-typing the same component every time
* This is a component that takes a value prop OR
* handles value as a state, internally, OR
* does both.
*
* It can also trigger the onChange event throttled,
* instead of doing so on every key stroke
*/
import * as React from 'react'
import { Component } from 'react'
export interface Props extends React.InputHTMLAttributes<HTMLInputElement>
{ submit?: (value: string) => void // when pressing enter
; change?: (value: string) => void // when changes occur
; value?:string // pass this to override internal value
; throttle?: number // send keystrokes every <throttle> ms. Defaults to 300
; handleChangeExternally?:boolean // if `true`, internal state handling is disabled. You're on your own
; renderer?: (props:InputRendererProps) => JSX.Element // render to any sort of markup you like
}
export interface State
{ value:string
}
export interface InputRendererProps
{ submitHandler: (evt: FormEvent<HTMLFormElement>) => any
, changeHandler: (evt: InputEvent<HTMLInputElement>) => any
, value: string
}
export const InputRenderer =
({ submitHandler, changeHandler, value }: InputRendererProps) =>
( <form onSubmit={submitHandler}>
<input type="text" onChange={changeHandler} value={value} />
</form>
)
export class Input extends Component<Props,State>
{ timer:number = 0
; static defaultProps:Props =
{ throttle: 300
, renderer: InputRenderer
}
; constructor(props:Props)
{ super(props)
; const value = ( typeof props.value == 'string' ? props.value+'' : '')
; this.state =
{ value
}
}
; submitHandler = (evt:FormEvent<HTMLFormElement>) =>
{ evt.preventDefault()
; if(this.props.submit)
{ this.props.submit(this.state.value)
}
}
; changeHandler = (evt:InputEvent<HTMLInputElement>) =>
{ evt.preventDefault()
; const value = evt.target.value
; const { change, throttle, handleChangeExternally } = this.props
; if( !change || !handleChangeExternally)
{ this.setState({value})
}
; if( change )
{ if (!handleChangeExternally && throttle )
{ clearTimeout(this.timer)
; this.timer = setTimeout( () => change(value), throttle)
}else
{ change(value)
}
}
}
; componentWillReceiveProps(nextProps:Partial<Props>)
{ if(nextProps.value !== this.props.value)
{ const {value} = nextProps
; if(typeof value === 'string')
{ this.setState({value})
}
}
}
; render()
{ const
{ submitHandler
, changeHandler
, props
, state
} = this
; const renderer = props.renderer || InputRenderer
; const
{ value } = state
; return React.createElement( renderer, { submitHandler, changeHandler, value })
}
}
export default Input
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment