One-line controlled and uncontrolled property binding for React
npm install use-binding
When developing React components, you often have to choose between providing a controlled (or "stateless") or uncontrolled ("stateful") version. For instance, if you have a custom Input component, do you:
- Provide a
defaultValue
prop and manage the state inside your component (uncontrolled), or do you: - Provide a
value
prop and expect the parent component to manage state for you (controlled)?
You may end up developing both variants, adding lots of boilerplate code.
useBinding
allows you to do both in one line.
Use this in your component:
const [myValue, setMyValue] = useBinding(
defaultValue,
value,
onChange,
fallbackValue /* optional */
);
Now use myValue
as your property value, and use setMyValue
whenever you want to change it. Everything works as expected. That means:
- If the consumer of your component passes a
value
, that value will be used. - If the consumer of your component passes a
defaultValue
, thenuseBinding
will useuseState
internally to keep track of the current value. - If both
defaultValue
andvalue
are empty, then thefallbackValue
will be used. ThefallbackValue
is optional: if you don't provide it either, thenmyValue
will be null. - If the consumer of your component passed an
onChange
handler, that handler will be called when usingsetMyValue
.
Consider the Input
example above. You can use useBinding
like this:
import React from 'react';
import { useBinding } from 'use-binding';
interface IInputProps {
defaultValue?: string
value?: string
onChange?: (newValue: string) => void
}
const CustomInput: React.FC<IInputProps> = ({ defaultValue, value, onChange }) => {
const [inputValue, setInputValue] = useBinding(defaultValue, value, onChange, '');
return (
<input type="text" value={inputValue} onChange={(e: ChangeEvent<HTMLInputElement>) => { setInputValue(e.target.value) })} />
);
};
This will give consumers of your CustomInput
component a lot of options:
// Controlled:
const [value, setValue] = useState('');
<CustomInput value={value} onChange={setValue} />;
// Uncontrolled:
<CustomInput defaultValue="my default" onChange={(newValue: string) => { console.log(newValue); })} />;
// Fixed value:
<CustomInput value="can't change me" />;
useBinding
supports Typescript and contains generic typings. Of course you can also use it in plain old Javascript.
Developed by Sebastiaan Besselsen at Sdu Uitgevers, The Netherlands.