Skip to content

Instantly share code, notes, and snippets.

@sibelius
Last active November 15, 2019 01:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sibelius/d44c23c1b50f2edb393718b0236dbb20 to your computer and use it in GitHub Desktop.
Save sibelius/d44c23c1b50f2edb393718b0236dbb20 to your computer and use it in GitHub Desktop.
useControlledState to provide a uncontrolled and controlled api for your components
import { useState } from 'react';
export const useControlledState = <T extends any>(value: T, onChange?: (value: T) => void) => {
const [uncontrolledValue, setUncontrolledValue] = useState(value);
if (typeof onChange === 'function') {
// Controlled version
return [value, onChange];
}
// Uncontrolled version
return [uncontrolledValue, setUncontrolledValue];
};
@jankowiakdawid
Copy link

jankowiakdawid commented Nov 14, 2019

I think we can improve typing on this hook, and avoid using any
Also mark second argument as optional

import { useState } from 'react';

export const useControlledState = <T>(value: T, onChange?: (value: T) => void) => {
  const [uncontrolledValue, setUncontrolledValue] = useState(value);
  if (typeof onChange === 'function') {
    // Controlled version
    return [value, onChange];
  }
  // Uncontrolled version
  return [uncontrolledValue, setUncontrolledValue];
};

@sibelius
Copy link
Author

tks, I was just lazy about typing properly \o/

@sibelius
Copy link
Author

there is just one problem with your typing, it should be

<T extends any>

typescript does not handle <> generics on .tsx files

@maraisr
Copy link

maraisr commented Nov 15, 2019

not true. Its not a tsx thing, it's the fact that arrow functions can't have "naked" generics. But you could also argue that it should'nt be a generic at all. Because all .value props from native inputs are strings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment