Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(react): add useControllableState #7980

Conversation

joshblack
Copy link
Contributor

We have several components that can be controlled or uncontrolled and have built up a couple of patterns for implementing this throughout the codebase. This PR introduces a custom useControllableState hook to start the discussion around what it would look like to standardize this pattern across the codebase.

For controlled versus uncontrolled components, a basic example of this is an <input>. This primitive can be uncontrolled or controlled:

function Uncontrolled() {
  return <input type="text" />
}

function Controlled() {
  const [value, setValue] = useState('');

  function onChange(event) {
    setValue(event.target.value);
  }

  return <input type="text" onChange={onChange} value={value} />;
}

One important note with this: switching from controlled to uncontrolled, or vice versa, is not supported.

To replicate this behavior for components we build, we would use useControllableState:

function TextInput({
  onChange: controlledOnChange,
  value: controlledValue,
}) {
  // Provide the controlled value and onChange along with the default value
  const [value, setValue] = useControllableState(controlledValue, controlledOnChange, '');

  function onChange(event) {
    setValue(event.target.value);
  }

  return (
    <input
      type="text"
      onChange={onChange}
      value={value}
    />
  );
}

We can then use the same component, TextInput, for both controlled and uncontrolled scenarios:

function Uncontrolled() {
  return <TextInput />;
}

function Controlled() {
  const [value, setValue] = useState('');
  
  function onChange(value) {
    setValue(value);
  }

  return <TextInput onChange={onChange} value={value} />;
}

Note: this was heavily inspired by a similar hook in [Chakra UI](https://chakra-ui.com/docs/hooks/use-controllable

Changelog

New

  • Add useControllableState hook for components that can be controlled or uncontrolled

Changed

@joshblack joshblack requested a review from a team as a code owner March 4, 2021 18:21
@netlify
Copy link

netlify bot commented Mar 4, 2021

Deploy preview for carbon-elements ready!

Built with commit 78984d6

https://deploy-preview-7980--carbon-elements.netlify.app

@netlify
Copy link

netlify bot commented Mar 4, 2021

Deploy preview for carbon-components-react ready!

Built with commit 78984d6

https://deploy-preview-7980--carbon-components-react.netlify.app

@netlify
Copy link

netlify bot commented Mar 4, 2021

Deploy preview for carbon-elements ready!

Built with commit 522af92

https://deploy-preview-7980--carbon-elements.netlify.app

@netlify
Copy link

netlify bot commented Mar 4, 2021

Deploy preview for carbon-components-react ready!

Built with commit 522af92

https://deploy-preview-7980--carbon-components-react.netlify.app

@dakahn
Copy link
Contributor

dakahn commented Mar 6, 2021

Thanks for walking me through this!

Base automatically changed from master to main March 8, 2021 16:35
@andreancardona andreancardona merged commit 51b1924 into carbon-design-system:main Mar 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants